下面就是源代码,其中部分很基本的代码我就省略掉了,编译平台为
Win2000 Server with SP2 + VC6.0 with SP5
#include <windows.h>
#include <winsock2.h>
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct _SOCKET_INFORMATION {
BOOL RecvPosted;
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
SOCKET Socket;
DWORD BytesSEND;
DWORD BytesRECV;
_SOCKET_INFORMATION *Next;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
#define WM_SOCKET (WM_USER + 1)
void CreateSocketInformation(SOCKET s, HWND);
LPSOCKET_INFORMATION GetSocketInformation(SOCKET s);
void FreeSocketInformation(SOCKET s);
LPSOCKET_INFORMATION SocketInfoList;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
DWORD Ret;
SOCKET Listen;
SOCKADDR_IN InternetAddr;
WSADATA wsaData;
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
// Prepare echo server
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
...
...
RegisterClass (&wndclass);
hwnd = CreateWindow (...) ; // creation parameters
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
MessageBox(hwnd, TEXT("Start socket failed"), TEXT("error"), MB_OK);
ExitProcess(1);
}
if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
MessageBox(hwnd, TEXT("socket() failed"), TEXT("error"), MB_OK);
ExitProcess(1);
}
WSAAsyncSelect(Listen, hwnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr))
== SOCKET_ERROR)
{
MessageBox(hwnd, TEXT("bind() failed"), TEXT("error"), MB_OK);
ExitProcess(1);
}
if (listen(Listen, 5))
{
MessageBox(hwnd, TEXT("listen() failed"), TEXT("error"), MB_OK);
ExitProcess(1);
}
// Translate and dispatch window messages for the application thread
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
SOCKET Accept;
LPSOCKET_INFORMATION SocketInfo;
DWORD RecvBytes, SendBytes;
DWORD Flags;
switch (message)
{
case WM_CREATE:
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, TEXT ("Server Started!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
case WM_SOCKET:
if (WSAGETSELECTERROR(lParam))
{
MessageBox(...);
FreeSocketInformation(wParam);
}
else
{
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET)
{
MessageBox(...);
break;
}
// Create a socket information structure to associate with the
// socket for processing I/O.
CreateSocketInformation(Accept, hwnd);
WSAAsyncSelect(Accept, hwnd, WM_SOCKET,
FD_READ|FD_WRITE|FD_CLOSE);
break;
case FD_READ:
SocketInfo = GetSocketInformation(wParam);
// Read data only if the receive buffer is empty.
if (SocketInfo->BytesRECV != 0)
{
SocketInfo->RecvPosted = TRUE;
return 0;
}
else
{
SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = DATA_BUFSIZE;
Flags = 0;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf),
1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
MessageBox(...);
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
SocketInfo->BytesRECV = RecvBytes;
}
// DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV.
// Go ahead and begin writing data to the client.
case FD_WRITE:
SocketInfo = GetSocketInformation(wParam);
if (SocketInfo->BytesRECV > SocketInfo->BytesSEND)
{
SocketInfo->DataBuf.buf =
SocketInfo->Buffer + SocketInfo->BytesSEND;
SocketInfo->DataBuf.len =
SocketInfo->BytesRECV - SocketInfo->BytesSEND;
if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf),
1, &SendBytes, 0,NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
MessageBox(...);
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
SocketInfo->BytesSEND += SendBytes;
}
if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
{
SocketInfo->BytesSEND = 0;
SocketInfo->BytesRECV = 0;
// If a RECV occurred during our SENDs then we need to post
// an FD_READ notification on the socket.
if (SocketInfo->RecvPosted == TRUE)
{
SocketInfo->RecvPosted = FALSE;
PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
}
}
if(SocketInfo->DataBuf.buf != NULL)
MessageBox(hwnd, SocketInfo->DataBuf.buf,
TEXT("Received"), MB_OK);
break;
case FD_CLOSE:
FreeSocketInformation(wParam);
break;
}
}
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
void CreateSocketInformation(SOCKET s, HWND hwnd)
{
LPSOCKET_INFORMATION SI;
if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)
{
MessageBox(...);
return;
}
// Prepare SocketInfo structure for use.
SI->Socket = s;
SI->RecvPosted = FALSE;
SI->BytesSEND = 0;
SI->BytesRECV = 0;
SI->Next = SocketInfoList;
SocketInfoList = SI;
}
LPSOCKET_INFORMATION GetSocketInformation(SOCKET s)
{
SOCKET_INFORMATION *SI = SocketInfoList;
while(SI)
{
if (SI->Socket == s)
return SI;
SI = SI->Next;
}
return NULL;
}
void FreeSocketInformation(SOCKET s)
{
SOCKET_INFORMATION *SI = SocketInfoList;
SOCKET_INFORMATION *PrevSI = NULL;
while(SI)
{
if (SI->Socket == s)
{
if (PrevSI)
PrevSI->Next = SI->Next;
else
SocketInfoList = SI->Next;
closesocket(SI->Socket);
GlobalFree(SI);
return;
}
PrevSI = SI;
SI = SI->Next;
}
}
服务器就这样建好了,只需要一个客户机就可以通信了,具体的代码我就不再贴了,各位可
以自己设计客户机,或者去下载区下载源程序。最后向大家推荐《Windows网络编程技术》,
真的不错。
本文中部分内容翻译自MSDN,客户机程序使用的是《Windows网络编程技术》中的例子