// Adopt a proxy server prototype code for completion port
Http://www.vckbase.com/code/listcode.asp?mclsid=9&sclsid=901
-------------------------------------------------- -------------
http://www.vctop.com/view.asp?id=484&cateid=1
-------------------------------------------------- -------------
Server program:
http://www.cnxbb.com/bcb/xbb_server_iocp.rar
Simulated multi-client program
http://www.cnxbb.com/bcb/echoclient.rar
-------------------------------------------------- -------------
// compile:
//
// Cl -O Callback Callback.cpp WS2_32.LIB
//
// Command Line Options:
//
// Callback.exe
//
// NOTE: There is no command line Options for this sample.
//
// Block mode overlapping model completion routine mechanism, Wang Tianping, 2003-06-20
//
#include
#include
#include
#define port 5150
#define data_bufsize 8192
// Sackage information array unit structure
Typedef struct _socket_information {
Overlapped overlapped; // overlapping structure
Socket socket; // socket
Char buffer [data_bufsize]; // wsarecv / wsasend data buffer pointer
WSABUF DATABUF; // WSARECV / WSasend Data Buffer
DWORD BYTESSEND; / / Send byte number
DWORD BYTESRECV; // Receive the number of bytes
} Socket_information, * lpsocket_information;
Void Callback WorkerRoutine (DWORD ERROR, DWORD BYTESTRANSFERRED,
LPWSAOVERLAPPED OVERLAPPED, DWORD INFLAGS;
DWORD WINAPI WORKERTHREAD (LPVOID LPPARETER);
Socket acceptsocket;
Void main (void)
{
Wsadata wsadata;
Socket Listensocket;
SockAddr_in internetdr;
Int R;
Handle threadhandle;
DWORD thREADID;
WSAEVENT ACCEPTEVENT;
IF ((RET = WSAStartup (0x0202, & wsadata))! = 0)
{
Printf ("WSAStartup Failed with Error% D / N", RET);
WSACLEANUP ();
Return;
}
IF ((listensocket = WSASOCKET (AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED) == Invalid_socket
{
Printf ("failed to get a socket% d / n", wsagetlasterror ());
Return;
}
InternetAddr.sin_Family = AF_INET;
InternetAddr.sin_addr.s_addr = HTONL (INADDR_ANY);
InternetAddr.sin_Port = HTONS (port);
IF (Bind (Lisoft (PSockAddr) & InternetDr,
SIZEOF (Internetdr)) == Socket_ERROR)
{
Printf ("Bind () failed with error% d / n", wsagetlasterror ());
Return;
}
IF (Listen (Listensocket, 5))
{
Printf ("Listen () failed with error% d / n", wsagetlasterror ());
Return;
}
IF ((AcceptEvent = WSACREATEEVENT ()) == WSA_INVALID_EVENT)
{
Printf ("WSACREATEEVENT () FAILED with ERROR% D / N", wsagetlasterror ());
Return;
}
// CREATE A WORKER Thread to Service Completed I / O Requests.
IF ((ThreadHandle = CreateThread (Null, 0, Workerthread, (LPVOID) Accept, 0, & ThreadID) == NULL)
{
Printf ("CreateThread Failed with Error% D / N", getLastError ());
Return;
}
While (True)
{
Acceptsocket = accept (listensocket, null, null);
IF (WsaseTevent (ACCEPTEVENT) == FALSE
{
Printf ("WsaseTevent Failed with Error% D / N", Wsagetlasterror ());
Return;
}
}
}
DWORD WINAPI WORKERTHREAD (LPVOID LPPARETER)
{
DWORD FLAGS;
LPSocket_INFORMATION SocketInfo;
WSAEVENT EventArray [1];
DWORD INDEX;
DWORD Recvbytes;
// save the accept event in the event array.
EventArray [0] = (wsaevent) LPPARETER;
While (True)
{
// Wait for accept () To Signal An Event and Also Process WorkerRoutine () Returns.
While (true) {
Index = WSAWAITFORMULTIPLEEVENTS (1, EventArray, False, WSA_INFINITE, TRUE);
IF (index == wsa_wait_failed)
{
Printf ("WSAWAITFORMULTIPLENTS FAILED with ERROR% D / N", wsagetlasterror ());
Return False;
}
IF (index! = wait_io_completion)
{
// an accept () Call Event is Ready - Break the Wait Loop
Break;
}
}
WSARESETEVENT (EventArray [INDEX - WSA_WAIT_EVENT_0]);
// Create a socket information structure to associate with the access socket.
IF ((SocketInfo = (LPSocket_information) Globalalloc (GPTR,
SIZEOF (socket_information))) == NULL)
{
PRINTF ("GlobalAlloc () Failed with Error% D / N", getLastError ());
Return False;
}
// Fill in the details of ot attcept socket.
SocketInfo-> Socket = Acceptsocket;
ZeromeMory (& (socketInfo-> overlapped), sizeof (wsaoverlapped);
SocketInfo-> bytessend = 0;
SocketInfo-> BytesRecv = 0;
SocketInfo-> databasef.len = DATA_BUFSIZE;
SocketInfo-> DatabaseF.Buf = SocketInfo-> Buffer;
Flags = 0;
IF (WSarecv (SocketInfo-> Socket, & (SocketInfo-> Database, 1, & Recvbytes, & Flags,
& (Socketinfo-> overlapped, workerroutine) == Socket_ERROR)
{
IF (wsagetlasterror ()! = WSA_IO_PENDING)
{
Printf ("WSARECV () Failed with Error% D / N", WsageTlasterror ());
Return False;
}
}
Printf ("Socket% D Connected / N", Acceptsocket;
}
Return True;
}
Void Callback WorkerRoutine (DWORD ERROR, DWORD BYTESTRANSFERRED,
LPWSAOVERLAPPED OVERLAPPED, DWORD INFLAGS
{
DWORD SendBytes, Recvbytes;
DWORD FLAGS;
// Reference The Wsaoverlapped Structure As A Socket_information StructureLPSocket_information Si = (LPSocket_information) overlapped;
IF (Error! = 0)
{
Printf ("I / O Operation Failed with Error% D / N", Error);
}
IF (ByTestransferred == 0)
{
Printf ("Closing Socket% D / N", Si-> Socket;
}
IF (Error! = 0 | | ByTestransferRed == 0)
{
CloseSocket (Si-> Socket);
GlobalFree (Si);
Return;
}
// Check to see if the bytesRecv field equals zero. If this is so, then
// this means a wsarecv call Just Completed SO Update the bytesrecv field
// with the bytestransferred value from the completed wsarecv () Call.
IF (Si-> BytesRecv == 0)
{
Si-> bytesrecv = bytestrionferred;
Si-> Bytessend = 0;
}
Else
{
Si-> bytessend = bytestrionferred;
}
IF (Si-> BytesRecv> Si-> Bytessend)
{
// post annother wsasend () Request.
// Since wsasend () is not gauranteed to send all of the bytes request,
// Continue Posting Wsasend () Calls UnTil All Received Bytes Are Sent.
ZeromeMory (& (Si-> Overlapped), SIZEOF (WSAOVERLAPPED);
Si-> DATABUF.BUF = Si-> Buffer Si-> bytessend;
Si-> databuf.len = si-> bytesrecv - si-> bytessend;
IF (Wsasend (Si-> Socket, & (Si-> Database), 1, & Sendbytes, 0,
& (Si-> Overlapped) == Socket_ERROR)
{
IF (wsagetlasterror ()! = WSA_IO_PENDING)
{
Printf ("Wsasend () failed with error% d / n", wsagetlasterror ());
Return;
}
}
}
Else
{
Si-> bytesRecv = 0;
// Now That there are no more bytes to send post annother wsarecv () request.flags = 0;
ZeromeMory (& (Si-> Overlapped), SIZEOF (WSAOVERLAPPED);
Si-> databasef.len = DATA_BUFSIZE;
Si-> DATABUF.BUF = Si-> Buffer;
IF (WSarecv (Si-> Socket, & (Si-> Database, & Flags,
& (Si-> Overlapped) == Socket_ERROR)
{
IF (wsagetlasterror ()! = WSA_IO_PENDING)
{
Printf ("WSARECV () Failed with Error% D / N", WsageTlasterror ());
Return;
}
}
}
}