WSASend 함수(winsock2.h)
WSASend 함수는 연결된 소켓에 데이터를 보냅니다.
구문
int WSAAPI WSASend(
[in] SOCKET s,
[in] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesSent,
[in] DWORD dwFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
매개 변수
[in] s
연결된 소켓을 식별하는 설명자입니다.
[in] lpBuffers
WSABUF 구조체 배열에 대한 포인터입니다. 각 WSABUF 구조체에는 버퍼에 대한 포인터와 버퍼의 길이(바이트)가 포함됩니다. Winsock 애플리케이션의 경우 WSASend 함수가 호출되면 시스템에서 이러한 버퍼를 소유하며 애플리케이션이 해당 버퍼에 액세스하지 못할 수 있습니다. 이 배열은 보내기 작업 기간 동안 유효한 상태로 유지되어야 합니다.
[in] dwBufferCount
lpBuffers 배열의 WSABUF 구조체 수입니다.
[out] lpNumberOfBytesSent
I/O 작업이 즉시 완료되는 경우 이 호출에서 보낸 숫자(바이트)에 대한 포인터입니다.
잠재적으로 잘못된 결과를 방지하려면 lpOverlapped 매개 변수가 NULL이 아닌 경우 이 매개 변수에 NULL을 사용합니다. lpOverlapped 매개 변수가 NULL이 아닌 경우에만 이 매개 변수는 NULL일 수 있습니다.
[in] dwFlags
WSASend 함수 호출의 동작을 수정하는 데 사용되는 플래그입니다. 자세한 내용은 주의 섹션에서 dwFlags 사용을 참조하세요.
[in] lpOverlapped
WSAOVERLAPPED 구조체에 대한 포인터입니다. 이 매개 변수는 오버랩되지 않은 소켓에 대해 무시됩니다.
[in] lpCompletionRoutine
형식: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
보내기 작업이 완료될 때 호출되는 완료 루틴에 대한 포인터입니다. 이 매개 변수는 오버랩되지 않은 소켓에 대해 무시됩니다.
반환 값
오류가 발생하지 않고 보내기 작업이 즉시 완료된 경우 WSASend 는 0을 반환합니다. 이 경우 호출 스레드가 경고 가능한 상태이면 완료 루틴이 이미 호출되도록 예약됩니다. 그렇지 않으면 SOCKET_ERROR 값이 반환되고 WSAGetLastError를 호출하여 특정 오류 코드를 검색할 수 있습니다. 오류 코드 WSA_IO_PENDING 겹치는 작업이 성공적으로 시작되었으며 나중에 완료가 표시됨을 나타냅니다. 다른 오류 코드는 겹치는 작업이 성공적으로 시작되지 않았으며 완료 표시가 발생하지 않음을 나타냅니다.
오류 코드 | 의미 |
---|---|
가상 회로가 시간 초과 또는 기타 오류로 인해 종료되었습니다. | |
스트림 소켓의 경우 원격 쪽에서 가상 회로를 다시 설정했습니다. 더 이상 소켓을 사용할 수 없으므로 응용 프로그램이 소켓을 닫아야 합니다. UDP 데이터그램 소켓의 경우 이 오류는 이전 보내기 작업으로 인해 ICMP "포트 연결할 수 없음" 메시지가 발생했음을 나타냅니다. | |
lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine 매개 변수는 사용자 주소 공간의 유효한 부분에 완전히 포함되지 않습니다. | |
차단 Windows 소켓 1.1 호출이 WSACancelBlockingCall을 통해 취소되었습니다. | |
차단 Windows Sockets 1.1 호출이 진행 중이거나 서비스 공급자가 여전히 콜백 함수를 처리하고 있습니다. | |
소켓이 바인딩 으로 바인딩되지 않았거나 소켓이 겹치는 플래그로 만들어지지 않았습니다. | |
소켓은 메시지 지향적이며 메시지는 기본 전송에서 지원하는 최대값보다 큽습니다. | |
네트워크 하위 시스템이 실패했습니다. | |
스트림 소켓의 경우 작업이 진행되는 동안 오류를 감지하는 연결 유지 작업으로 인해 연결이 끊어졌습니다. 데이터그램 소켓의 경우 이 오류는 TTL(Time to Live)이 만료되었음을 나타냅니다. | |
Windows 소켓 공급자는 버퍼 교착 상태를 보고합니다. | |
소켓이 연결되지 않았습니다. | |
설명자가 소켓이 아닙니다. | |
MSG_OOB 지정되었지만 소켓이 SOCK_STREAM 형식과 같은 스트림 스타일이 아니거나, OOB 데이터가 이 소켓과 연결된 통신 도메인에서 지원되지 않거나, MSG_PARTIAL 지원되지 않거나, 소켓이 단방향이며 수신 작업만 지원합니다. | |
소켓이 종료되었습니다. SD_SEND 또는 SD_BOTH 로 설정된 방법을 사용하여 종료가 호출된 후에는 소켓에서 WSASend할 수 없습니다. | |
Windows NT:
겹치는 소켓: 미해결 겹치는 I/O 요청이 너무 많습니다. 오버랩되지 않은 소켓: 소켓이 차단 해제로 표시되고 보내기 작업을 즉시 완료할 수 없습니다. |
|
이 함수를 사용하기 전에 성공적인 WSAStartup 호출이 발생해야 합니다. | |
겹치는 작업이 성공적으로 시작되었으며 나중에 완료가 표시됩니다. | |
소켓의 닫기, WSAIoctl에서 "SIO_FLUSH" 명령 실행 또는 작업이 완료되기 전에 겹친 요청을 시작한 스레드로 인해 겹치는 작업이 취소되었습니다. 자세한 내용은 주의 섹션을 참조하세요. |
설명
WSASend 함수는 다음 두 가지 중요한 영역에서 표준 송신 함수 이상의 기능을 제공합니다.
WSASend 함수는 s로 지정된 연결 지향 소켓에 하나 이상의 버퍼에서 나가는 데이터를 쓰는 데 사용됩니다. 그러나 connect 또는 WSAConnect 함수를 통해 규정된 기본 피어 주소가 설정된 연결 없는 소켓에서도 사용할 수 있습니다.소켓 함수에서 만든 소켓 에는 겹치는 특성이 기본값으로 있습니다. WSA_FLAG_OVERLAPPED 비트 집합을 사용하여 WSASocket에 전달된 dwFlags 매개 변수를 사용하여 WSASocket 함수에서 만든 소켓에는 겹치는 특성이 있습니다. 겹치는 특성이 있는 소켓의 경우 lpOverlapped 및 lpCompletionRoutine 매개 변수가 모두 NULL이 아닌 한 WSASend는 겹치는 I/O를 사용합니다. 이 경우 소켓은 겹치지 않는 소켓으로 처리됩니다. 전송에서 버퍼를 사용한 경우 이벤트 개체의 루틴 또는 설정 완료를 호출하는 완료 표시가 발생합니다. 작업이 즉시 완료되지 않으면 완료 루틴 또는 WSAGetOverlappedResult를 통해 최종 완료 상태 검색됩니다.
lpOverlapped 및 lpCompletionRoutine이 모두 NULL인 경우 이 함수의 소켓은 겹치지 않는 소켓으로 처리됩니다.
겹치지 않는 소켓의 경우 마지막 두 매개 변수(lpOverlapped, lpCompletionRoutine)는 무시되고 WSASend 는 send와 동일한 차단 의미 체계를 채택합니다. 데이터는 버퍼에서 전송 버퍼로 복사됩니다. 소켓이 비차단 및 스트림 지향이고 전송 버퍼에 충분한 공간이 없는 경우 WSASend 는 애플리케이션 버퍼의 일부만 사용된 상태로 반환됩니다. 동일한 버퍼 상황과 차단 소켓을 감안할 때 WSASend 는 모든 애플리케이션 버퍼 콘텐츠가 소비될 때까지 차단됩니다.
메시지 지향 소켓의 경우 소 켓 옵션 SO_MAX_MSG_SIZE 값을 가져와서 가져올 수 있는 기본 공급자의 최대 메시지 크기를 초과하지 마세요. 데이터가 기본 프로토콜을 통해 원자성으로 전달하기에 너무 길면 WSAEMSGSIZE 오류가 반환되고 데이터가 전송되지 않습니다.
Windows Me/98/95: WSASend 함수는 16개 이상의 버퍼를 지원하지 않습니다.
dwFlags 사용
dwFlags 매개 변수를 사용하여 연결된 소켓에 대해 지정된 옵션 외에 함수 호출의 동작에 영향을 줄 수 있습니다. 즉, 이 함수의 의미 체계는 소켓 옵션 및 dwFlags 매개 변수에 의해 결정됩니다. 후자는 다음 표에 나열된 값과 함께 비트 OR 연산자를 사용하여 생성됩니다.값 | 의미 |
---|---|
MSG_DONTROUTE | 데이터가 라우팅의 대상이 되어서는 안 되도록 지정합니다. Windows 소켓 서비스 공급자는 이 플래그를 무시하도록 선택할 수 있습니다. |
MSG_OOB | SOCK_STREAM 같은 스트림 스타일 소켓에 OOB 데이터를 보냅니다. |
MSG_PARTIAL | lpBuffers에 부분 메시지만 포함되도록 지정합니다. 오류 코드 WSAEOPNOTSUPP 는 부분 메시지 전송을 지원하지 않는 전송에서 반환됩니다. |
겹치는 소켓 I/O
겹치는 작업이 즉시 완료되면 WSASend 는 0 값을 반환하고 lpNumberOfBytesSent 매개 변수는 전송된 바이트 수로 업데이트됩니다. 겹치는 작업이 성공적으로 시작되고 나중에 완료될 경우 WSASend 는 SOCKET_ERROR 반환하고 오류 코드 WSA_IO_PENDING 나타냅니다. 이 경우 lpNumberOfBytesSent 는 업데이트되지 않습니다. 겹치는 작업이 완료되면 전송되는 데이터의 양은 완료 루틴의 cbTransferred 매개 변수를 통해(지정된 경우) 또는 WSAGetOverlappedResult의 lpcbTransfer 매개 변수를 통해 표시됩니다.lpOverlapped 매개 변수는 겹치는 작업 기간 동안 유효해야 합니다. 여러 I/O 작업이 동시에 미해결 상태이면 각각 별도의 WSAOVERLAPPED 구조를 참조해야 합니다.
lpCompletionRoutine 매개 변수가 NULL이면 유효한 이벤트 개체 핸들이 포함된 경우 겹치는 작업이 완료될 때 lpOverlapped의 hEvent 매개 변수가 신호를 보냅니다. 애플리케이션은 WSAWaitForMultipleEvents 또는 WSAGetOverlappedResult 를 사용하여 이벤트 개체를 기다리거나 폴링할 수 있습니다.
lpCompletionRoutine이 NULL이 아닌 경우 hEvent 매개 변수는 무시되며 애플리케이션에서 컨텍스트 정보를 완료 루틴에 전달하는 데 사용할 수 있습니다. NULL이 아닌 lpCompletionRoutine을 전달하고 나중에 동일한 겹치는 I/O 요청에 대해 WSAGetOverlappedResult를 호출하는 호출자는 WSAGetOverlappedResult 호출에 대한 fWait 매개 변수를 TRUE로 설정하지 않을 수 있습니다. 이 경우 hEvent 매개 변수의 사용은 정의되지 않으며 hEvent 매개 변수를 기다리려고 하면 예기치 않은 결과가 생성됩니다.
완료 루틴은 Windows 파일 I/O 완료 루틴에 규정된 것과 동일한 규칙을 따릅니다. true로 설정된 fAlertable 매개 변수가 있는 WSAWaitForMultipleEvents 함수가 호출될 때와 같이 스레드가 경고 대기 상태에 있을 때까지 완료 루틴이 호출되지 않습니다.
전송 공급자를 사용하면 애플리케이션이 소켓 I/O 완료 루틴의 컨텍스트 내에서 송신 및 수신 작업을 호출할 수 있으며 지정된 소켓의 경우 I/O 완료 루틴이 중첩되지 않도록 보장합니다. 이렇게 하면 시간이 중요한 데이터 전송이 선점 컨텍스트 내에서 완전히 발생할 수 있습니다.
다음 C++ 코드 예제는 완료 루틴의 프로토타입입니다.
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine 함수는 애플리케이션 정의 또는 라이브러리 정의 함수 이름의 자리 표시자입니다. dwError 매개 변수는 lpOverlapped로 표시된 대로 겹치는 작업에 대한 완료 상태 지정합니다. cbTransferred는 전송된 바이트 수를 지정합니다. 현재 플래그 값이 정의되어 있지 않으며 dwFlags는 0이 됩니다. 이 함수는 값을 반환하지 않습니다.
이 함수에서 반환하면 이 소켓에 대해 보류 중인 다른 완료 루틴을 호출할 수 있습니다. 경고 가능한 스레드의 대기가 반환 코드 WSA_IO_COMPLETION 충족되기 전에 모든 대기 완료 루틴이 호출됩니다. 완료 루틴은 겹치는 작업이 완료되는 순서와 같은 순서로 호출할 수 있는 것은 아닙니다. 그러나 게시된 버퍼는 지정된 순서대로 전송되도록 보장됩니다.
WSASend 호출 순서는 버퍼가 전송 계층으로 전송되는 순서이기도 합니다. 일부 Winsock 공급자는 큰 송신 요청을 여러 전송으로 분할할 수 있으며, 이로 인해 동일한 스트림 지향 소켓의 여러 동시 전송 요청에서 의도하지 않은 데이터가 인터리빙될 수 있으므로 WSASend는 서로 다른 스레드에서 동시에 동일한 스트림 지향 소켓에서 호출되어서는 안 됩니다.
예제 코드
다음 코드 예제에서는 겹치는 I/O 모드에서 WSASend 함수를 사용하는 방법을 보여 줍니다.#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#define DATA_BUFSIZE 4096
#define SEND_COUNT 10
int __cdecl main()
{
WSADATA wsd;
struct addrinfo *result = NULL;
struct addrinfo hints;
WSAOVERLAPPED SendOverlapped;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET AcceptSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD SendBytes;
DWORD Flags;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc, i;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
printf("Unable to load Winsock: %d\n", rc);
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID) & hints, sizeof(struct addrinfo));
// Initialize the hints to obtain the
// wildcard bind address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
rc = getaddrinfo(NULL, "27015", &hints, &result);
if (rc != 0) {
printf("getaddrinfo failed with error: %d\n", rc);
return 1;
}
ListenSocket = socket(result->ai_family,
result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}
rc = bind(ListenSocket, result->ai_addr, (int) result->ai_addrlen);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
rc = listen(ListenSocket, 1);
if (rc == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
// Accept an incoming connection request
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
printf("Client Accepted...\n");
// Make sure the SendOverlapped struct is zeroed out
SecureZeroMemory((PVOID) & SendOverlapped, sizeof (WSAOVERLAPPED));
// Create an event handle and setup the overlapped structure.
SendOverlapped.hEvent = WSACreateEvent();
if (SendOverlapped.hEvent == NULL) {
printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
closesocket(AcceptSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
for (i = 0; i < SEND_COUNT; i++) {
rc = WSASend(AcceptSocket, &DataBuf, 1,
&SendBytes, 0, &SendOverlapped, NULL);
if ((rc == SOCKET_ERROR) &&
(WSA_IO_PENDING != (err = WSAGetLastError()))) {
printf("WSASend failed with error: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE,
TRUE);
if (rc == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents failed with error: %d\n",
WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes,
FALSE, &Flags);
if (rc == FALSE) {
printf("WSASend failed with error: %d\n", WSAGetLastError());
break;
}
printf("Wrote %d bytes\n", SendBytes);
WSAResetEvent(SendOverlapped.hEvent);
}
WSACloseEvent(SendOverlapped.hEvent);
closesocket(AcceptSocket);
closesocket(ListenSocket);
freeaddrinfo(result);
WSACleanup();
return 0;
}
Windows Phone 8: 이 함수는 Windows Phone 8 이상에서 Windows Phone 스토어 앱에서 지원됩니다.
Windows 8.1 및 Windows Server 2012 R2: 이 함수는 Windows 8.1, Windows Server 2012 R2 이상에서 Windows 스토어 앱에서 지원됩니다.
요구 사항
요구 사항 | 값 |
---|---|
지원되는 최소 클라이언트 | Windows 8.1, Windows Vista [데스크톱 앱 | UWP 앱] |
지원되는 최소 서버 | Windows Server 2003 [데스크톱 앱 | UWP 앱] |
대상 플랫폼 | Windows |
헤더 | winsock2.h |
라이브러리 | Ws2_32.lib |
DLL | Ws2_32.dll |