Winsock provides a very useful asynchronous I/O model. With this model, applications can connect
Receives network event notifications Based on Windows messages. This model first appeared in Winsock.
In Version 1.1
Help developers to design for some early 16-bit Windows platforms. However, the current application can still
Even the csocket class in MFC adopts this model.
Because the model is based on the Windows message mechanism, to use this model, you must create a window.
Windows will be used to receive messages. Create a socket, call the wsaasyncselect function, and open the window.
Message notification. The function prototype is as follows:
Int wsaasyncselect (socket S, hwnd, unsigned int umsg, long Levent );
S is the socket we want, hwnd is the window handle for receiving notifications, and wmsg parameter is specified in
Messages to be accepted when a network event occurs are usually set to a value greater than that of wm_user to avoid message conflicts;
Levent specifies a single-bit mask, which corresponds to a combination of a series of network events, as shown in the following table:
Event |
Description |
Fd_read |
The program wants to receive notifications about whether the program can read data. |
Fd_write |
The program wants to receive write notifications to write data. |
Fd_oob |
The program wants to receive notifications about the arrival of OOB data |
Fd_accept |
The program wants to receive notifications related to the connection |
Fd_connect |
The program wants to receive notifications related to one connection or multi-point access. |
Fd_close |
The program wants to receive notifications related to socket disabling. |
Fd_qos |
The program wants to receive notifications of changes to the socket's "QoS ". |
Fd_group_qos |
It is useless for the moment. It is a reserved event. |
Fd_routing_interface_change |
The program wants to receive notifications about changes to the routing interface of the specified address. |
Fd_address_list_change |
The program wants to receive notifications of local address changes |
After the program successfully calls wsaasyncselect on a socket, the program will
The corresponding window routine receives network event notifications in the form of Windows messages. Window routines are usually defined as follows:
Lresult callback wndproc (hwnd, uint message, wparam,
Lparam
Lparam)
The wparam parameter specifies the socket on which a network event occurs. If multiple sockets are defined
Parameters are very important. The lparam parameter contains two important information. Its low-level characters specify
Generated network events, and high-level characters contain possible error codes.
To put it simply, the specific process of using this model is:
When a network message arrives at a window routine, the program first checks the high byte of lparam to determine whether it is in the socket
A network error occurred. The ready-made macros are already available here.
-->
Wsagetselecterror, which can be used to return
Return the error message contained in the high byte. If no error is found, determine the type of network.
The event triggers this Windows message, and this operation also has a ready-made macro
--> Wsagetselectevent
The following is the source code. I will omit some of the basic code.
Win2000 Server with SP2 + vc6.0
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
Hprevinstance,
Lpstr lpcmdline, int ncmdshow)
{
DWORD
RET;
Socket listen;
Sockaddr_in internetaddr;
Wsadata
Wsadata;
Static tchar szappname [] = text ("hellowin ");
Hwnd
;
MSG;
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, 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, uint message,
Wparam,
Lparam)
{
HDC;
Paintstruct pS;
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
Socket information structure to associate with
// Socket
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;
}
}
The server is created in this way, and only one client is needed for communication. I will not post the specific code. You can
Design your own client, or download the source program in the download area. Finally, we recommend windows network programming technology,
Really good.
Part of this article is translated from msdn. The client program uses an example in Windows network programming technology.