//
/*
。 7-8 ,
, , , 。
:
① , , 。
② 。
③ WSAOVERLAPPED 。
④ WSARecv , WSAOVERLAPPED ,
。
⑤ fAlertable TRUE , WSAWaitForMultipleEvents,
I/O 。 , , WSAWaitForMultipleEvents
WSA_IO_COMPLETION。 , , WSARecv 。
⑥ WSAWaitForMultipleEvents WSA_IO_COMPLETION。
⑦ ⑤ ⑥ 。
7-8 I/O
// : I/O ,
,
*/
// 。 5150 TCP
// ,
// ,
// :cl -o overlap overlap.cpp ws2_32.lib
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct _SOCKET_INFORMATION {
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
SOCKET Socket;
WSAOVERLAPPED Overlapped;
DWORD BytesSEND;
DWORD BytesRECV;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
DWORD EventTotal = 0; //
DWORD WINAPI ProcessIO(LPVOID lpParameter);
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
LPSOCKET_INFORMATION SocketArray[WSA_MAXIMUM_WAIT_EVENTS];
CRITICAL_SECTION CriticalSection;
int main(void)
{
WSADATA wsaData;
SOCKET ListenSocket, AcceptSocket;
SOCKADDR_IN InternetAddr;
DWORD Flags;
DWORD ThreadId;
DWORD RecvBytes;
INT Ret;
InitializeCriticalSection(&CriticalSection); //
printf("
") ;
if ((Ret = WSAStartup(0x0202,&wsaData)) != 0)
{
printf("WSAStartup failed with error %d
", Ret);
WSACleanup();
return 0 ;
}
if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) //
{
printf("Failed to get a socket %d
", WSAGetLastError());
return 0 ;
}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(ListenSocket, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) ==
SOCKET_ERROR) //
{
printf("bind() failed with error %d
", WSAGetLastError());
return 0 ;
}
if (listen(ListenSocket, 5))
{
printf("listen() failed with error %d
", WSAGetLastError());
return 0 ;
}
//
if ((AcceptSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) //
{
printf("Failed to get a socket %d
", WSAGetLastError());
return 0 ;
}
if ((EventArray[0] = WSACreateEvent()) == WSA_INVALID_EVENT) //
{
printf("WSACreateEvent failed with error %d
", WSAGetLastError());
return 0 ;
}
//
printf("
") ;
if (CreateThread(NULL, 0, ProcessIO, NULL, 0, &ThreadId) == NULL) // ThreadIO, ProcessIO ?
{
printf("CreateThread failed with error %d
", GetLastError());
return 0 ;
}
EventTotal = 1; //
int i = 0 ;
while(TRUE)
{
//
printf("Main %d
",i+1) ;
i++ ;
printf(" ,
") ;
if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) == INVALID_SOCKET)
{
printf("accept failed with error %d
", WSAGetLastError());
return 0 ;
}
EnterCriticalSection(&CriticalSection); // ??
//
if ((SocketArray[EventTotal] = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)
{
printf("GlobalAlloc() failed with error %d
", GetLastError());
return 0 ;
}
//
SocketArray[EventTotal]->Socket = AcceptSocket; // ?
ZeroMemory(&(SocketArray[EventTotal]->Overlapped), sizeof(OVERLAPPED));
SocketArray[EventTotal]->BytesSEND = 0;
SocketArray[EventTotal]->BytesRECV = 0;
SocketArray[EventTotal]->DataBuf.len = DATA_BUFSIZE;
SocketArray[EventTotal]->DataBuf.buf = SocketArray[EventTotal]->Buffer;
if ((SocketArray[EventTotal]->Overlapped.hEvent = EventArray[EventTotal] =
WSACreateEvent()) == WSA_INVALID_EVENT) //
{
printf("WSACreateEvent() failed with error %d
", WSAGetLastError());
return 0;
}
// WSARecv
Flags = 0;
if (WSARecv(SocketArray[EventTotal]->Socket,
&(SocketArray[EventTotal]->DataBuf), 1, &RecvBytes, &Flags,
&(SocketArray[EventTotal]->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d
", WSAGetLastError());
return 0;
}
}
EventTotal++;
printf("
") ;
LeaveCriticalSection(&CriticalSection);
// ,
if (WSASetEvent(EventArray[0]) == FALSE)
{
printf("WSASetEvent failed with error %d
", WSAGetLastError());
return 0 ;
}
}//while
return 0 ;
}
DWORD WINAPI ProcessIO(LPVOID lpParameter)
{
DWORD Index;
DWORD Flags;
LPSOCKET_INFORMATION SI;
DWORD BytesTransferred;
DWORD i;
DWORD RecvBytes, SendBytes;
printf(" ProcessIO
") ;
int j = 0 ;
// WSASend、WSARecv
while(TRUE)
{
printf("ProcessIO %d
",j+1) ;
j++ ;
if ((Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE,
WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents failed %d
", WSAGetLastError());
return 0;
}
// ,
if ((Index - WSA_WAIT_EVENT_0) == 0) // 0 , ? ?
{
WSAResetEvent(EventArray[0]);
continue;
}
SI = SocketArray[Index - WSA_WAIT_EVENT_0];
WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
if (WSAGetOverlappedResult(SI->Socket, &(SI->Overlapped), &BytesTransferred,
FALSE, &Flags) == FALSE || BytesTransferred == 0)
{
printf("Closing socket %d
", SI->Socket);
if (closesocket(SI->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d
", WSAGetLastError());
}
GlobalFree(SI);
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
// SocketArray EventArray
EnterCriticalSection(&CriticalSection); // 。。
if ((Index - WSA_WAIT_EVENT_0) + 1 != EventTotal)
for (i = Index - WSA_WAIT_EVENT_0; i < EventTotal; i++)
{
EventArray[i] = EventArray[i + 1];
SocketArray[i] = SocketArray[i + 1];
}
EventTotal--;
LeaveCriticalSection(&CriticalSection); //
continue;
}
// BytesRECV 0, WSARecv ,
//
// WSARecv BytesTransferred BytesRECV
if (SI->BytesRECV == 0)
{
SI->BytesRECV = BytesTransferred;
SI->BytesSEND = 0;
}
else
{
SI->BytesSEND += BytesTransferred;
}
if (SI->BytesRECV > SI->BytesSEND)
{
// WSASend() , WSASend() ,
//
// WSASend()
ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));
SI->Overlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];
SI->DataBuf.buf = SI->Buffer + SI->BytesSEND;
SI->DataBuf.len = SI->BytesRECV - SI->BytesSEND;
if (WSASend(SI->Socket, &(SI->DataBuf), 1, &SendBytes, 0,
&(SI->Overlapped), NULL) == SOCKET_ERROR) //
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() failed with error %d
", WSAGetLastError());
return 0;
}
}
}
else
{
SI->BytesRECV = 0;
// WSARecv
Flags = 0;
ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));
SI->Overlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];
SI->DataBuf.len = DATA_BUFSIZE;
SI->DataBuf.buf = SI->Buffer;
if (WSARecv(SI->Socket, &(SI->DataBuf), 1, &RecvBytes, &Flags,
&(SI->Overlapped), NULL) == SOCKET_ERROR) //
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d
", WSAGetLastError());
return 0;
}
}
else
{
// printf(" : %s",SI->DataBuf ) ;
}
}
}
printf(" ProcessIO
") ;
}
//
/*
6-2 , , ,
。 , 。 ,
。 。
TCP 。
, 。 , , 。 ,
, 。 , TCP
, , , , ,
。 , -O 。 ,
, 。
:
server -p:5150 -o
:
client -p:5150 -s:IP -n:10 -o
10 send , recv ,
10 。
*/
// 6-2
// : , TCP , ,
// :cl -o Client Client.c ws2_32.lib
//
// :
// client [-p:x] [-s:IP] [-n:x] [-o]
// -p:x
// -s:IP IP
// -n:x
// -o ,
//
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "Ws2_32.lib ")
#define DEFAULT_COUNT 10
#define DEFAULT_PORT 5150
#define DEFAULT_BUFFER 2048
#define DEFAULT_MESSAGE "This is a test of the emergency \
broadcasting system"
char szServer[128], //
szMessage[1024]; //
int iPort = DEFAULT_PORT; //
DWORD dwCount = DEFAULT_COUNT; //
BOOL bSendOnly = FALSE; // ,
void usage() ;
void ValidateArgs(int argc, char **argv) ;
// :main
// : , Winsock, , , ,
//
//
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET sClient;
char szBuffer[DEFAULT_BUFFER];
int ret,i;
struct sockaddr_in server;
struct hostent *host = NULL;
// Winsock
ValidateArgs(argc, argv);
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock library!
");
return 1;
}
strcpy(szMessage, DEFAULT_MESSAGE);
// ,
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
printf("socket() failed: %d
", WSAGetLastError());
return 1;
}
server.sin_family = AF_INET;
server.sin_port = htons(iPort);
server.sin_addr.s_addr = inet_addr(szServer);
// "aaa.bbb.ccc.ddd", ,
if (server.sin_addr.s_addr == INADDR_NONE)
{
host = gethostbyname(szServer);
if (host == NULL)
{
printf("Unable to resolve server: %s
", szServer);
return 1;
}
CopyMemory(&server.sin_addr, host->h_addr_list[0],
host->h_length);
}
if (connect(sClient, (struct sockaddr *)&server,sizeof(server)) == SOCKET_ERROR)
{
printf("connect() failed: %d
", WSAGetLastError());
return 1;
}
//
for(i = 0; i < dwCount; i++)
{
ret = send(sClient, szMessage, strlen(szMessage), 0);
if (ret == 0)
break;
else if (ret == SOCKET_ERROR)
{
printf("send() failed: %d
", WSAGetLastError());
break;
}
printf("Send %d bytes
", ret);
if (!bSendOnly)
{
ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0);
if (ret == 0) // Graceful close
break;
else if (ret == SOCKET_ERROR)
{
printf("recv() failed: %d
", WSAGetLastError());
break;
}
szBuffer[ret] = '\0';
printf("RECV [%d bytes]: '%s'
", ret, szBuffer);
}
}
closesocket(sClient);
WSACleanup();
return 0;
}
void usage()
{
printf("usage: client [-p:x] [-s:IP] [-n:x] [-o]
");
printf(" -p:x Remote port to send to
");
printf(" -s:IP Server's IP address or hostname
");
printf(" -n:x Number of times to send message
");
printf(" -o Send messages only; don't receive
");
ExitProcess(1);
}
// :ValidateArgs
// : ,
void ValidateArgs(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
switch (tolower(argv[i][1]))
{
case 'p': // Remote port
if (strlen(argv[i]) > 3)
iPort = atoi(&argv[i][3]);
break;
case 's': // Server
if (strlen(argv[i]) > 3)
strcpy(szServer, &argv[i][3]);
break;
case 'n': // Number of times to send message
if (strlen(argv[i]) > 3)
dwCount = atol(&argv[i][3]);
break;
case 'o': // Only send message; don't receive
bSendOnly = TRUE;
break;
default:
usage();
break;
}
}
}
}