(100分)IOCP(完成端口)初学者希望用代码加以代述 ( 积分: 100 )

  • 主题发起人 asksomeone
  • 开始时间
A

asksomeone

Unregistered / Unconfirmed
GUEST, unregistred user!
unit&nbsp;Mains;<br><br>interface<br><br>uses&nbsp;Windows,&nbsp;WinSock2,&nbsp;WinSock,&nbsp;Sysutils;<br><br>const<br>PORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;5150;<br>DATA_BUFSIZE&nbsp;=&nbsp;8192;<br><br><br>type<br>&nbsp;&nbsp;LPVOID&nbsp;=&nbsp;Pointer;&nbsp;//定义一个指针<br>&nbsp;&nbsp;LPPER_IO_OPERATION_DATA&nbsp;=&nbsp;^&nbsp;PER_IO_OPERATION_DATA&nbsp;;//一个指向数据集地址的指针吧?<br>&nbsp;&nbsp;PER_IO_OPERATION_DATA&nbsp;=&nbsp;packed&nbsp;record&nbsp;&nbsp;//开始定义数据集<br>&nbsp;&nbsp;&nbsp;&nbsp;Overlapped:&nbsp;OVERLAPPED;&nbsp;//重叠操作吧??<br>&nbsp;&nbsp;&nbsp;&nbsp;DataBuf:&nbsp;TWSABUF;&nbsp;//和上面的那个重叠,是固定的结构类型<br>&nbsp;&nbsp;&nbsp;&nbsp;Buffer:&nbsp;array&nbsp;[0..DATA_BUFSIZE]&nbsp;of&nbsp;CHAR;&nbsp;//定义一个字符数组&nbsp;&nbsp;是用来保存接受数据的缓存<br>&nbsp;&nbsp;&nbsp;&nbsp;BytesSEND:&nbsp;DWORD;&nbsp;//&nbsp;&nbsp;用来标志发送数据的长度。<br>&nbsp;&nbsp;&nbsp;&nbsp;BytesRECV:&nbsp;DWORD;&nbsp;//&nbsp;用来标志接收数据的长度<br>&nbsp;&nbsp;end;<br>&nbsp;&nbsp;{上面的结构中Overlapped:&nbsp;OVERLAPPED;和DataBuf:&nbsp;TWSABUF;是固定的结构类型。<br>&nbsp;&nbsp;Buffer:&nbsp;array&nbsp;[0..1024]&nbsp;of&nbsp;CHAR;是用来保存接受数据的缓存。<br>&nbsp;&nbsp;BytesSEND:&nbsp;DWORD;用来标志发送数据的长度。<br>&nbsp;&nbsp;BytesRECV:&nbsp;DWORD;用来标志接受数据的长度。<br>&nbsp;&nbsp;因为完成端口的工作者线程可以接受到来自客户端的数据,<br>&nbsp;&nbsp;同时还可以接受到自己发送给客户端的数据,所以我们使用BytesSEND,<br>&nbsp;&nbsp;BytesRECV变量来说是用来区分这次的数据是来自客户端的数据还是自己发送出去的数据。}<br><br>&nbsp;&nbsp;{单句柄数据结构}<br>&nbsp;&nbsp;LPPER_HANDLE_DATA&nbsp;=&nbsp;^&nbsp;PER_HANDLE_DATA;<br>&nbsp;&nbsp;PER_HANDLE_DATA&nbsp;=&nbsp;packed&nbsp;record<br>&nbsp;&nbsp;&nbsp;&nbsp;Socket:&nbsp;TSocket;<br>&nbsp;&nbsp;end;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;procedure&nbsp;main;<br><br>implementation<br><br>function&nbsp;ServerWorkerThread(CompletionPortID:&nbsp;LPVOID):&nbsp;DWORD;&nbsp;stdcall;&nbsp;forward;<br><br>procedure&nbsp;printf(Fmt:&nbsp;string;&nbsp;num:&nbsp;Integer);<br>begin<br>&nbsp;&nbsp;WriteLn(Format(Fmt,&nbsp;[num]));<br>end;<br><br>procedure&nbsp;main;<br>var<br>&nbsp;&nbsp;InternetAddr:&nbsp;SOCKADDR_IN;<br>&nbsp;&nbsp;Listen:&nbsp;TSOCKET;<br>&nbsp;&nbsp;Accept:&nbsp;TSOCKET;<br>&nbsp;&nbsp;CompletionPort:&nbsp;THANDLE&nbsp;;<br>&nbsp;&nbsp;SystemInfo:&nbsp;SYSTEM_INFO&nbsp;;<br>&nbsp;&nbsp;PerHandleData:&nbsp;LPPER_HANDLE_DATA&nbsp;;<br>&nbsp;&nbsp;PerIoData:&nbsp;LPPER_IO_OPERATION_DATA&nbsp;;<br>&nbsp;&nbsp;i:&nbsp;Integer;<br>&nbsp;&nbsp;RecvBytes:&nbsp;&nbsp;DWORD;<br>&nbsp;&nbsp;Flags:&nbsp;DWORD;<br>&nbsp;&nbsp;ThreadID:&nbsp;DWORD&nbsp;;<br>&nbsp;&nbsp;wsaData:&nbsp;TWSADATA&nbsp;;<br>&nbsp;&nbsp;Ret:&nbsp;DWORD&nbsp;;<br><br>&nbsp;&nbsp;ThreadHandle:&nbsp;THANDLE;<br>begin<br>&nbsp;&nbsp;&nbsp;&nbsp;Ret&nbsp;:=&nbsp;WSAStartup($0202,&nbsp;wsaData);<br>&nbsp;&nbsp;&nbsp;&nbsp;{应用程序或DLL只能在一次成功的WSAStartup()<br>&nbsp;&nbsp;&nbsp;&nbsp;调用之后才能调用进一步的Windows&nbsp;Sockets&nbsp;API函数<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAStartup()的另一个作用是获得Windows&nbsp;Sockets&nbsp;API的版本号。<br>&nbsp;&nbsp;&nbsp;&nbsp;$0202应该是表明现在用的是版本2.2的winsock<br>&nbsp;&nbsp;&nbsp;&nbsp;http://www.delphibbs.com/keylife/iblog_show.asp?xid=16839}<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(Ret&nbsp;&lt;&gt;&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSAStartup&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;Ret);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;//&nbsp;Setup&nbsp;an&nbsp;I/O&nbsp;completion&nbsp;port.<br>&nbsp;&nbsp;{创建一个完成端口&nbsp;CreateIoCompletionPort(FileHandle,&nbsp;ExistingCompletionPort:&nbsp;THandle;<br>&nbsp;&nbsp;CompletionKey,&nbsp;NumberOfConcurrentThreads:&nbsp;DWORD):&nbsp;THandle;}<br>&nbsp;&nbsp;CompletionPort&nbsp;:=&nbsp;CreateIoCompletionPort(INVALID_HANDLE_VALUE,&nbsp;0,&nbsp;0,&nbsp;0);<br>&nbsp;&nbsp;{第一个是windows常量吧INVALID_HANDLE_VALUE}<br>&nbsp;&nbsp;if&nbsp;(CompletionPort&nbsp;=&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&nbsp;'CreateIoCompletionPort&nbsp;failed&nbsp;with&nbsp;error:&nbsp;%d',&nbsp;GetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit;<br>&nbsp;&nbsp;end;<br>&nbsp;&nbsp;{如果得到的句柄是0,那就表示没有创建成功!返回错误}<br><br>&nbsp;&nbsp;//&nbsp;Determine&nbsp;how&nbsp;many&nbsp;processors&nbsp;are&nbsp;on&nbsp;the&nbsp;system.<br>&nbsp;&nbsp;{获取当前系统里有几颗处理器}<br>&nbsp;&nbsp;GetSystemInfo(SystemInfo);<br><br>&nbsp;&nbsp;//&nbsp;Create&nbsp;worker&nbsp;threads&nbsp;based&nbsp;on&nbsp;the&nbsp;number&nbsp;of&nbsp;processors&nbsp;available&nbsp;on&nbsp;the<br>&nbsp;&nbsp;//&nbsp;system.&nbsp;Create&nbsp;two&nbsp;worker&nbsp;threads&nbsp;for&nbsp;each&nbsp;processor.<br>{&nbsp;&nbsp;根据CPU的数量创建CPU*2数量的工作者线程。}<br>&nbsp;&nbsp;for&nbsp;i:=&nbsp;0&nbsp;to&nbsp;SystemInfo.dwNumberOfProcessors&nbsp;*&nbsp;2&nbsp;-&nbsp;1&nbsp;do<br>&nbsp;&nbsp;begin<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Create&nbsp;a&nbsp;server&nbsp;worker&nbsp;thread&nbsp;and&nbsp;pass&nbsp;the&nbsp;completion&nbsp;port&nbsp;to&nbsp;the&nbsp;thread.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{建立一个服务器工作线程并传递完成端口号给线程,当然要捕捉错误}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadHandle&nbsp;:=&nbsp;CreateThread(nil,&nbsp;0,&nbsp;@ServerWorkerThread,&nbsp;Pointer(CompletionPort),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,&nbsp;ThreadID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{function&nbsp;CreateThread(lpThreadAttributes:&nbsp;Pointer;<br>&nbsp;&nbsp;dwStackSize:&nbsp;DWORD;&nbsp;lpStartAddress:&nbsp;TFNThreadStartRoutine;<br>&nbsp;&nbsp;lpParameter:&nbsp;Pointer;&nbsp;dwCreationFlags:&nbsp;DWORD;&nbsp;var&nbsp;lpThreadId:&nbsp;DWORD):&nbsp;THandle;&nbsp;stdcall;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ThreadHandle&nbsp;=&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('CreateThread()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;GetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Close&nbsp;the&nbsp;thread&nbsp;handle<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{关闭线程句柄}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(ThreadHandle);<br>&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;//&nbsp;Create&nbsp;a&nbsp;listening&nbsp;socket<br>&nbsp;&nbsp;{function&nbsp;WSASocket(&nbsp;af:&nbsp;u_int;&nbsp;atype:&nbsp;u_int;&nbsp;protocol:&nbsp;u_int;<br>&nbsp;&nbsp;&nbsp;&nbsp;lpProtocolInfo:&nbsp;PWSAPROTOCOL_INFOA;&nbsp;g:&nbsp;TGroup;&nbsp;dwFlags:&nbsp;Dword)<br>&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;TSocket;&nbsp;stdcall;}<br>&nbsp;&nbsp;Listen&nbsp;:=&nbsp;WSASocket(AF_INET,&nbsp;SOCK_STREAM,&nbsp;0,&nbsp;nil,&nbsp;0,&nbsp;WSA_FLAG_OVERLAPPED);<br>&nbsp;&nbsp;{创建一个与指定传送服务提供者捆绑的套接口,可选地创建和/或加入一个套接口组。<br>&nbsp;&nbsp;&nbsp;af:地址族描述。目前仅支持PF_INET格式,亦即ARPA&nbsp;Internet地址格式。<br>&nbsp;&nbsp;&nbsp;type:新套接口的类型描述。<br>&nbsp;&nbsp;&nbsp;protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。<br>&nbsp;&nbsp;&nbsp;lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该结构定义所创建套接口的特性。如果本参数非零,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;则前三个参数(af,&nbsp;type,protocol)被忽略。<br>&nbsp;&nbsp;&nbsp;g:套接口组的描述字。<br>&nbsp;&nbsp;&nbsp;iFlags:套接口属性描述。<br><br>&nbsp;&nbsp;返回值:<br>&nbsp;&nbsp;&nbsp;&nbsp;若无错误发生,WSASocket()返回新套接口的描述字。<br>&nbsp;&nbsp;&nbsp;&nbsp;否则的话,返回&nbsp;INVALID_SOCKET,应用程序可定调<br>&nbsp;&nbsp;&nbsp;&nbsp;用WSAGetLastError()来获取相应的错误代码。<br><br>&nbsp;&nbsp;错误代码:<br>&nbsp;&nbsp;&nbsp;&nbsp;WSANOTINITIALISED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在调用本API之前应成功调用WSAStartup()。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAENETDOWN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;网络子系统失效。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEAFNOSUPPORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不支持指定的地址族。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEINPROGRESS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEMFILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;无可用的套接口描述字。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAENOBUFS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;无可用的缓冲区空间。套接口无法创建。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEPROTONOSUPPORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不支持指定的协议。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEPROTOTYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定的协议对于本套接口类型错误。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAESOCKTNOSUPPORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本地址族不支持指定的套接口类型。<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAEINVAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g参数非法。<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;if&nbsp;(Listen&nbsp;=&nbsp;INVALID_SOCKET)&nbsp;then<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSASocket()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;end;<br><br><br>&nbsp;&nbsp;InternetAddr.sin_family&nbsp;:=&nbsp;AF_INET;&nbsp;&nbsp;{SOCKET.AF_INET:0...127}<br>&nbsp;&nbsp;InternetAddr.sin_addr.s_addr&nbsp;:=&nbsp;htonl(INADDR_ANY);{&nbsp;SOCKET.htonl():integer;}<br>&nbsp;&nbsp;InternetAddr.sin_port&nbsp;:=&nbsp;htons(PORT);<br><br>&nbsp;&nbsp;{sin&nbsp;_family为网络地址类型,必须设定为AF_INET。<br>&nbsp;&nbsp;sin_port为服务端口,注意不要使用已固定的服务端口,如HTTP的端口80等。<br>&nbsp;&nbsp;如果端口设置为0,则系统会自动分配一个唯一端口。<br>&nbsp;&nbsp;sin_addr为一个unsigned&nbsp;long的IP地址。<br>&nbsp;&nbsp;sin_zero为填充字段,纯粹用来保证结构的大小。<br>&nbsp;&nbsp;◆&nbsp;将常用的用点分开的IP地址转换为unsigned&nbsp;long类型的IP地址的函数:<br>&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;inet_addr(const&nbsp;char&nbsp;FAR&nbsp;*&nbsp;cp&nbsp;)<br>&nbsp;&nbsp;&nbsp;用法:<br>&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;addr=inet_addr(&quot;192.1.8.84&quot;)<br><br>&nbsp;&nbsp;&nbsp;◆&nbsp;如果将sin_addr设置为INADDR_ANY,则表示所有的IP地址,也即所有的计算机。<br>&nbsp;&nbsp;&nbsp;#define&nbsp;INADDR_ANY&nbsp;(u_long)0x00000000<br><br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;{绑定端口}<br>&nbsp;&nbsp;if&nbsp;(bind(Listen,&nbsp;InternetAddr,&nbsp;sizeof(InternetAddr))&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('bind()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;//&nbsp;Prepare&nbsp;socket&nbsp;for&nbsp;listening<br><br><br>&nbsp;&nbsp;{第二个表示可接受的最大等待数<br>&nbsp;&nbsp;int&nbsp;PASCAL&nbsp;FAR&nbsp;listen(&nbsp;SOCKET&nbsp;s,&nbsp;int&nbsp;backlog);<br><br>&nbsp;&nbsp;S:用于标识一个已捆绑未连接套接口的描述字。<br>&nbsp;&nbsp;backlog:等待连接队列的最大长度。}<br>&nbsp;&nbsp;if&nbsp;(Winsock.listen(Listen,&nbsp;5)&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('listen()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;end<br>&nbsp;&nbsp;else<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('Server&nbsp;listen&nbsp;on&nbsp;port&nbsp;=&nbsp;%d&nbsp;...',&nbsp;PORT);<br>&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;{创建一个套接字,将此套接字和一个端口绑定并监听此端口。}<br>&nbsp;&nbsp;//&nbsp;Accept&nbsp;connections&nbsp;and&nbsp;assign&nbsp;to&nbsp;the&nbsp;completion&nbsp;port.<br>&nbsp;&nbsp;while(TRUE)&nbsp;do<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;{当客户端有连接请求的时候,WSAAccept函数会新创建一个套接字Acceptsc。<br>&nbsp;&nbsp;这个套接字就是和客户端通信的时候使用的套接字。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Accept&nbsp;:=&nbsp;WSAAccept(Listen,&nbsp;nil,&nbsp;nil,&nbsp;nil,&nbsp;0);<br>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据条件函数的返回值有条件地接受连接,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同时(可选地)创建和/或加入一个套接口组。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;WSAAPI&nbsp;WSAAccept&nbsp;(&nbsp;SOCKET&nbsp;s,&nbsp;struct<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockaddr&nbsp;FAR&nbsp;*&nbsp;addr,&nbsp;int&nbsp;FAR&nbsp;*&nbsp;addrlen,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPCONDITIONPROC&nbsp;lpfnCondition,&nbsp;DWORD<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwCallbackData&nbsp;);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s:标识一个套接口的描述字,该套接口在listen()后监听连接。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr:(可选)指针,指向存放通讯层所知的连接实体地址的缓冲区。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr参数的具体格式由套接口创建时产生的地址族决定。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addrlen:(可选)指针,指向存放addr地址长度的整形数。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpfnCondition:(可选的)用户提供的条件函数的进程实例地址。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该函数根据参数传入的调用者信息作出接受或拒绝的决定,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;并通过给结果参数赋予特定的值来(可选地)创建和/或加<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;入一个套接口组。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwCallbackData:作为条件函数参数返回给应用程序的回调数据。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WinSock不分析该参数。<br><br>&nbsp;&nbsp;&nbsp;返回值:<br>&nbsp;&nbsp;&nbsp;&nbsp;若无错误发生,WSAAccept()函数返回所接受套接口的描述字。<br>&nbsp;&nbsp;&nbsp;&nbsp;否则的话,将返回INVALID_SOCKET错误,应用程序可通过<br>&nbsp;&nbsp;&nbsp;&nbsp;WSAGetLastError()来获取相应的错误代码。<br>&nbsp;&nbsp;&nbsp;&nbsp;addrlen参数引用的整形数初始时包含了addr参数所指向的空间数,<br>&nbsp;&nbsp;&nbsp;&nbsp;在调用返回时包含了返回地址的实际长度。<br><br>&nbsp;&nbsp;&nbsp;错误代码:<br>&nbsp;&nbsp;&nbsp;WSANOTINITIALISED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在调用本API之前应成功调用WSAStartup()。<br>&nbsp;&nbsp;&nbsp;WSAECONNREFUSED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据条件函数的返回值(CF_REJECT)强制拒绝连接请求。<br>&nbsp;&nbsp;&nbsp;WSAENETDOWN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;网络子系统失效。<br>&nbsp;&nbsp;&nbsp;WSAEFAULT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addrlen参数太小(小于sockaddr结构的大小),或者lpfnCondition并不是用户空间的一部分。<br>&nbsp;&nbsp;&nbsp;WSAEINTR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过WSACancelBlockingCall()函数取消(阻塞)调用。<br>&nbsp;&nbsp;&nbsp;WSAEINPROGRESS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个阻塞WinSock调用正在进行。<br>&nbsp;&nbsp;&nbsp;WSAEINVAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WSAAccept()调用前未执行listen()调用;条件函数中的g参数非法;条件函数的返回值非法;套接口处于非法状态。<br>&nbsp;&nbsp;&nbsp;WSAEMFILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WSAAccept()调用时排队队列非空,且无可用套接口描述字。<br>&nbsp;&nbsp;&nbsp;WSAENOBUFS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;无可用缓冲区空间。<br>&nbsp;&nbsp;&nbsp;WSAENOTSOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述字不是一个套接口。<br>&nbsp;&nbsp;&nbsp;WSAEOPNOTSUPP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所引用的套接口不是支持面向连接服务类型的。<br>&nbsp;&nbsp;&nbsp;WSATRY_AGAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据条件函数的返回值(CF_DEFER)&nbsp;,连接请求被推迟。<br>&nbsp;&nbsp;&nbsp;WSAEWOULDBLOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;套接口标志为非阻塞,无连接请求供接受。<br>&nbsp;&nbsp;&nbsp;WSAEACCES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;被推迟的连接请求超时或撤销。<br>}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(Accept&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSAAccept()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;{判断Acceptsc套接字创建是否成功,如果不成功则退出。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Create&nbsp;a&nbsp;socket&nbsp;information&nbsp;structure&nbsp;to&nbsp;associate&nbsp;with&nbsp;the&nbsp;socket<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{创建一个“单句柄数据结构”将Acceptsc套接字绑定。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerHandleData&nbsp;:=&nbsp;LPPER_HANDLE_DATA&nbsp;(GlobalAlloc(GPTR,&nbsp;sizeof(PER_HANDLE_DATA)));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(PerHandleData&nbsp;=&nbsp;nil)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('GlobalAlloc()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Associate&nbsp;the&nbsp;accepted&nbsp;socket&nbsp;with&nbsp;the&nbsp;original&nbsp;completion&nbsp;port.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('Socket&nbsp;number&nbsp;%d&nbsp;connected',&nbsp;Accept);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerHandleData.Socket&nbsp;:=&nbsp;Accept;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{将套接字、完成端口和“单句柄数据结构”三者绑定在一起。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(CreateIoCompletionPort(Accept,&nbsp;CompletionPort,&nbsp;DWORD(PerHandleData),&nbsp;0)&nbsp;=&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('CreateIoCompletionPort()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Create&nbsp;per&nbsp;I/O&nbsp;socket&nbsp;information&nbsp;structure&nbsp;to&nbsp;associate&nbsp;with&nbsp;the&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;WSARecv&nbsp;call&nbsp;below.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{将套接字、完成端口和“单句柄数据结构”三者绑定在一起。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData&nbsp;:=&nbsp;LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR,&nbsp;sizeof(PER_IO_OPERATION_DATA)));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(PerIoData&nbsp;=&nbsp;nil)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('GlobalAlloc()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{创建一个“单IO数据结构”其中将PerIoData.BytesSEND&nbsp;和PerIoData.BytesRECV&nbsp;均设置成0。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;说明此“单IO数据结构”是用来接受的。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(&nbsp;@PerIoData.Overlapped,&nbsp;sizeof(OVERLAPPED));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesSEND&nbsp;:=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesRECV&nbsp;:=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.len&nbsp;:=&nbsp;DATA_BUFSIZE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.buf&nbsp;:=&nbsp;@PerIoData.Buffer;<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在重叠模型中,接收数据就要靠它了,它的参数也比recv要多,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为要用刀重叠结构嘛,它是这样定义的:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;WSARecv(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;当然是投递这个操作的套接字<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPWSABUF&nbsp;lpBuffers,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;接收缓冲区,与Recv函数不同<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这里需要一个由WSABUF结构构成的数组<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwBufferCount,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数组中WSABUF结构的数量<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPDWORD&nbsp;lpNumberOfBytesRecvd,&nbsp;&nbsp;//&nbsp;如果接收操作立即完成,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里会返回函数调用所接收到的字节数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPDWORD&nbsp;lpFlags,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;说来话长了,我们这里设置为0&nbsp;即可<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPWSAOVERLAPPED&nbsp;lpOverlapped,&nbsp;&nbsp;//&nbsp;“绑定”的重叠结构<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPWSAOVERLAPPED_COMPLETION_ROUTINE&nbsp;lpCompletionRoutine<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;完成例程中将会用到的参数,我们这里设置为&nbsp;NULL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br><br>返回值:<br>&nbsp;&nbsp;&nbsp;WSA_IO_PENDING&nbsp;:&nbsp;最常见的返回值,这是说明我们的WSARecv操作成功了,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;但是I/O操作还没有完成,所以我们就需要绑定一个事件来通知我们操作何时完成<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flags&nbsp;:=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSARecv(Accept,&nbsp;@(PerIoData.DataBuf),&nbsp;1,&nbsp;@RecvBytes,&nbsp;@Flags,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@(PerIoData.Overlapped),&nbsp;nil)&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSAGetLastError()&nbsp;&lt;&gt;&nbsp;ERROR_IO_PENDING)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSARecv()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br>end;<br>&nbsp;{上面参照http://blog.csdn.net/jedli/archive/2007/06/29/1671969.aspx}<br><br><br>{下面的参照}<br>function&nbsp;ServerWorkerThread(CompletionPortID:&nbsp;LPVOID):&nbsp;DWORD;&nbsp;stdcall;<br>var<br>&nbsp;&nbsp;CompletionPort:&nbsp;THANDLE;<br>&nbsp;&nbsp;BytesTransferred:&nbsp;DWORD&nbsp;;<br>//&nbsp;&nbsp;Overlapped:&nbsp;POVERLAPPED;<br>&nbsp;&nbsp;PerHandleData:&nbsp;LPPER_HANDLE_DATA&nbsp;;<br>&nbsp;&nbsp;PerIoData:&nbsp;LPPER_IO_OPERATION_DATA&nbsp;;<br>&nbsp;&nbsp;SendBytes,&nbsp;RecvBytes:&nbsp;DWORD;<br>&nbsp;&nbsp;Flags:&nbsp;DWORD&nbsp;;<br>begin<br>&nbsp;&nbsp;CompletionPort&nbsp;:=&nbsp;THANDLE(&nbsp;CompletionPortID);<br>&nbsp;&nbsp;{得到创建线程是传递过来的IOCP}<br>&nbsp;&nbsp;Result:=&nbsp;0;<br><br>&nbsp;&nbsp;while(TRUE)&nbsp;do<br>&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{工作者线程会停止到GetQueuedCompletionStatus函数处,直到接受到数据为止}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(GetQueuedCompletionStatus(CompletionPort,&nbsp;BytesTransferred,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD(PerHandleData),&nbsp;POverlapped(PerIoData),&nbsp;INFINITE)&nbsp;=&nbsp;False)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('GetQueuedCompletionStatus&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;GetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{当客户端连接断开或者客户端调用closesocket函数的时候,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数GetQueuedCompletionStatus会返回错误。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果我们加入心跳后,在这里就可以来判断套接字是否依然在连接。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;First&nbsp;check&nbsp;to&nbsp;see&nbsp;if&nbsp;an&nbsp;error&nbsp;has&nbsp;occured&nbsp;on&nbsp;the&nbsp;socket&nbsp;and&nbsp;if&nbsp;so<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;then&nbsp;close&nbsp;the&nbsp;socket&nbsp;and&nbsp;cleanup&nbsp;the&nbsp;SOCKET_INFORMATION&nbsp;structure<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;associated&nbsp;with&nbsp;the&nbsp;socket.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{当客户端连接断开或者客户端调用closesocket函数的时候,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数GetQueuedCompletionStatus会返回错误。如果我们加入心跳后,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在这里就可以来判断套接字是否依然在连接。}<br><br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(BytesTransferred&nbsp;=&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{当客户端调用shutdown函数来从容断开的时候,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们可以在这里进行处理。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('Closing&nbsp;socket&nbsp;%d/',&nbsp;PerHandleData.Socket);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(closesocket(PerHandleData.Socket)&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('closesocket()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GlobalFree(DWORD(PerHandleData));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GlobalFree(DWORD(PerIoData));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Check&nbsp;to&nbsp;see&nbsp;if&nbsp;the&nbsp;BytesRECV&nbsp;field&nbsp;equals&nbsp;zero.&nbsp;If&nbsp;this&nbsp;is&nbsp;so,&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;this&nbsp;means&nbsp;a&nbsp;WSARecv&nbsp;call&nbsp;just&nbsp;completed&nbsp;so&nbsp;update&nbsp;the&nbsp;BytesRECV&nbsp;field<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;with&nbsp;the&nbsp;BytesTransferred&nbsp;value&nbsp;from&nbsp;the&nbsp;completed&nbsp;WSARecv()&nbsp;call.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{我们来判断数据的来自方向。因为我们发送出去数据的时候我们设置了<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结构成员BytesSEND。所以如果BytesRECV=0同时BytesSEND=0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么此数据就是我们接受到的客户端数据。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(这种区分方法不是唯一的,个人可以有自己的定义方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;只要可以区分开数据来源就可以。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(PerIoData.BytesRECV&nbsp;=&nbsp;0)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesRECV&nbsp;:=&nbsp;BytesTransferred;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesSEND&nbsp;:=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesSEND&nbsp;:=&nbsp;PerIoData.BytesSEND&nbsp;+&nbsp;BytesTransferred;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{当是接受来自客户端的数据是,我们进行数据的处理。}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(PerIoData.BytesRECV&nbsp;&gt;&nbsp;PerIoData.BytesSEND)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Post&nbsp;another&nbsp;WSASend()&nbsp;request.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Since&nbsp;WSASend()&nbsp;is&nbsp;not&nbsp;gauranteed&nbsp;to&nbsp;send&nbsp;all&nbsp;of&nbsp;the&nbsp;bytes&nbsp;requested,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;continue&nbsp;posting&nbsp;WSASend()&nbsp;calls&nbsp;until&nbsp;all&nbsp;received&nbsp;bytes&nbsp;are&nbsp;sent.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(@(PerIoData.Overlapped),&nbsp;sizeof(OVERLAPPED));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{这时变量PerIoData.Buffer就是接受到的客户端数据。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据的长度是PerIoData.DataBuf.len&nbsp;你可以对数据进行相关的处理了}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.buf&nbsp;:=&nbsp;PerIoData.Buffer&nbsp;+&nbsp;PerIoData.BytesSEND;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.len&nbsp;:=&nbsp;PerIoData.BytesRECV&nbsp;-&nbsp;PerIoData.BytesSEND;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSASend(PerHandleData.Socket,&nbsp;@(PerIoData.DataBuf),&nbsp;1,&nbsp;@SendBytes,&nbsp;0,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@(PerIoData.Overlapped),&nbsp;nil)&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSAGetLastError()&nbsp;&lt;&gt;&nbsp;ERROR_IO_PENDING)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSASend()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.BytesRECV&nbsp;:=&nbsp;0;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Now&nbsp;that&nbsp;there&nbsp;are&nbsp;no&nbsp;more&nbsp;bytes&nbsp;to&nbsp;send&nbsp;post&nbsp;another&nbsp;WSARecv()&nbsp;request.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flags&nbsp;:=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(@(PerIoData.Overlapped),&nbsp;sizeof(OVERLAPPED));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.len&nbsp;:=&nbsp;DATA_BUFSIZE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerIoData.DataBuf.buf&nbsp;:=&nbsp;@PerIoData.Buffer;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSARecv(PerHandleData.Socket,&nbsp;@(PerIoData.DataBuf),&nbsp;1,&nbsp;@RecvBytes,&nbsp;@Flags,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@(PerIoData.Overlapped),&nbsp;nil)&nbsp;=&nbsp;SOCKET_ERROR)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(WSAGetLastError()&nbsp;&lt;&gt;&nbsp;ERROR_IO_PENDING)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf('WSARecv()&nbsp;failed&nbsp;with&nbsp;error&nbsp;%d',&nbsp;WSAGetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;end;<br>end;<br><br><br>end.<br>小弟不是学网络编程的,所以对socket函数也了解不深,如果问的问题让大家见笑了,笑过之后请明示一下改怎么做,谢谢<br>1,我想知道,这是一个单句柄的完成端口,是什么意思,是不是实际应用当中不是这样子的<br>2,我想知道,它的客户端怎么写<br>3,我想知道,完成端口怎么和数据库通讯,进行增删改查的工作<br>希望大家畅所欲言,小弟无以为报,就以300分,献给教我学习的大富翁们~
 
不懂,顶一下
 
1.单句柄数据就是和句柄对应的数据,像socket句柄,文件句柄这种东西<br>2.客户端和服务器的(模型)类型没关系,你平时怎么写客户端现在依然照写,不用改变<br>3.在服务端要有相应的代码,客户端不能直接操纵服务端的数据库,网络只传数据,服务端收到数据或操作指令后再对数据库进行操作,你要有用程序操作数据库的经验(分布式数据库除外)
 
代码太乱了.....一个巨大的函数做完一切工作.....
 
白大哥,是有点乱,是网上的代码,我自己为了学习方便标注的,你能不能给我个服务端客户端的DEMO看看,小弟的邮箱是asksomeone2002@yahoo.com.cn<br>一个人自学,闷着头,很郁闷啊,有高手帮帮小弟吧,从开始到现在,我都是一个人开发,到了这一步,没有人帮一把,我实在是混不下去了,今天我还在看代码,资料,一大堆地读,啃也要啃下去,用C++描述的,唉
 
参看&nbsp;下&nbsp;,顶下等高人
 
var<br>&nbsp;&nbsp;wsaData:TWSADATA;<br>&nbsp;&nbsp;s:TSOCKET;<br>&nbsp;&nbsp;ServerAddr:SOCKADDR_IN;<br>&nbsp;&nbsp;n:integer=2;<br>const&nbsp;Port&nbsp;=&nbsp;5150;<br><br>procedure&nbsp;TForm1.Button1Click(Sender:&nbsp;TObject);<br>begin<br>WSAStartup(MAKEWORD(2,2),wsaData);<br>s&nbsp;:=&nbsp;socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);<br>ServerAddr.sin_family&nbsp;:=&nbsp;AF_INET;<br>ServerAddr.sin_port&nbsp;:=&nbsp;htons(Port);<br>ServerAddr.sin_addr.s_addr&nbsp;:=inet_addr('192.168.1.104');&nbsp;//inet_addr('136.149.3.29');<br>connect(s,ServerAddr,sizeof(ServerAddr));<br>//send(s,n,sizeof(n),0);这一句有事<br>WSACleanup();<br><br><br>end;<br>自己写了一段,可以连上,怎么发送数据,在服务端可以看到?
 
参考:&nbsp;http://www.delphibbs.com/delphibbs/dispq.asp?lid=3627212&nbsp;顺便说一声,你那段代码是《WINDOWS网络编程技术》那本书上的c版本改写的,既然你能看懂c++代码不如直接看《WINDOWS网络编程技术》。网上有电子书的。
 
是的,我看C++有点难度,但还是可以,谢谢棒场,其实我很矛盾,呵呵,对socket有抵触心,就算能联上,我也不知道怎么去用,我心里想的是把读取的客户端发来的数据,然后在服务端用ADOquery查询后的结果,再转成数据,通过完成端口发送给客户端,是这样子的吗
 
IOCP被神化了呀
 
看看我给你的例子,数据的收发基本上就是那样子了,剩下的就是对数据库的操作了,其实和单机上的操作没有什么区别。你要自己定义一个简单的传输协议,最基本的是要把数据和指令区分开来。祝你好运!
 
谢谢各位,今天是周五了,等周一就结账,100分有些少了,不行了另开散分贴
 
asksomeone<br>你写的客户端有问题。<br>你写的测试客户端只是链接了一下服务端,然后就关闭了。WSACleanup();<br>根本就没有发送数据给服务端。
 
找一下《WINDOWS网络编程技术》看,可能对你有帮助。
 
这属于通迅类的问题吧?怎么跑到&quot;数据库-C/S&quot;型里面了?
 
好了,多谢各位,就这样子吧,我再找找资料看看,特别感谢newsmile的帮助
 
分不多,如有争议,我再开贴给分也成,呵呵,先就这样吧
 
补充一点,其实发现用indy中的tcpclient就能联上并发送数据
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
933
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部