同样要使用线程:
procedure tlistenthread.execute;
var
hevent : wsaevent;
ret : integer;
ne : twsanetworkevents;
sock : tsocket;
adr : tsockaddrin;
smsg : string;
index,
eventtotal : dword;
eventarray : array [0..wsa_maximum_wait_events-1] of wsaevent;
begin
...socket...bind...
hevent := wsacreateevent();
wsaeventselect( listensock, hevent, fd_accept or fd_close );
...listen...
while ( not terminated ) do
begin
index := wsawaitformultipleevents( eventtotal, @eventarray[0], false, wsa_infinite, false );
fillchar( ne, sizeof(ne), 0 );
wsaenumnetworkevents( sockarray[index-wsa_wait_event_0], eventarray[index-wsa_wait_event_0], @ne );
if ( ne.lnetworkevents and fd_accept ) > 0 then
begin
if ne.ierrorcode[fd_accept_bit] <> 0 then
continue;
ret := sizeof(adr);
sock := accept( sockarray[index-wsa_wait_event_0], adr, ret );
if eventtotal > wsa_maximum_wait_events-1 then//这里wsa_maximum_wait_events同样是64
begin
closesocket( sock );
continue;
end;
hevent := wsacreateevent();
wsaeventselect( sock, hevent, fd_read or fd_write or fd_close );
sockarray[eventtotal] := sock;
eventarray[eventtotal] := hevent;
inc( eventtotal );
end;
if ( ne.lnetworkevents and fd_read ) > 0 then
begin
if ne.ierrorcode[fd_read_bit] <> 0 then
continue;
fillchar( recvbuf[0], pack_size_receive, 0 );
ret := recv( sockarray[index-wsa_wait_event_0], recvbuf[0], pack_size_receive, 0 );
......
end;
end;
end;
四:overlapped i/o 事件通知模型
后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了!
overlapped i/o 事件通知模型和wsaeventselect模型在实现上非常相似,主要区别在“overlapped”,overlapped模型是让应用程序使用重叠数据结构(wsaoverlapped),一次投递一个或多个winsock i/o请求。这些提交的请求完成后,应用程序会收到通知。什么意思呢?就是说,如果你想从socket上接收数据,只需要告诉系统,由系统为你接收数据,而你需要做的只是为系统提供一个缓冲区~~~~~
listen线程和wsaeventselect模型一模一样,recv/send线程则完全不同:
procedure toverlapthread.execute;
var
dwtemp : dword;
ret : integer;
index : dword;
begin
......
while ( not terminated ) do
begin
index := wsawaitformultipleevents( flinks.count, @flinks.events[0], false, recv_time_out, false );
dec( index, wsa_wait_event_0 );
if index > wsa_maximum_wait_events-1 then //超时或者其他错误
continue;
wsaresetevent( flinks.events[index] );
wsagetoverlappedresult( flinks.sockets[index], flinks.poverlaps[index], @dwtemp, false, flinks.pdwflags[index]^ );
if dwtemp = 0 then //连接已经关闭
begin
......
continue;
end else
begin
fmmain.listbox1.items.add( flinks.pbufs[index]^.buf );
end;
//初始化缓冲区
flinks.pdwflags[index]^ := 0;
fillchar( flinks.poverlaps[index]^, sizeof(wsaoverlapped), 0 );
flinks.poverlaps[index]^.hevent := flinks.events[index];
fillchar( flinks.pbufs[index]^.buf^, buffer_size, 0 );
//递一个接收数据请求
wsarecv( flinks.sockets[index], flinks.pbufs[index], 1, flinks.pdwrecvd[index]^, flinks.pdwflags[index]^, flinks.poverlaps[index], nil );
end;
end;
五:overlapped i/o 完成例程模型
老陈接收到新的信件后,一般的程序是:打开信封----掏出信纸----阅读信件----回复信件......为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信/阅读/回复了!老陈终于过上了小资生活!