| 发表于:2008-01-17 16:19:06 楼主 |
我写的一个客户端收发主线程。刚开始线程可以正常收发, 但在有的电脑上运行一段时间后只能发不能收。 服务端是使用完成端口完成的,也可以正常给客户端发送数据。 以下是我的主线程,代码,请高手指点指点。 拜。。。。。。。。。。。。。。。。 unit u_mainthread; interface uses windows, messages, sysutils, variants, classes, graphics, controls, forms, dialogs, stdctrls, syncobjs, extctrls,shareunit,iocpcomp, scktcomp,winsock2; type trecmsgevent = procedure(arecstr: string) of object; tclientthread=class(tthread) private fhost: string; faddmsg: trecmsgevent; fsocket: tclientwinsocket; lastrecvtest: tdatetime; //最后收到测试字符串的时间 protected procedure EXECute; override; public constructor create(ahost: string; aaddmsg: trecmsgevent); destructor destroy; override; end; { tclient } implementation uses u_wy108clientmain; constructor tclientthread.create; begin freeonterminate := true; inherited create(false); lastrecvtest := now(); fhost := ahost; faddmsg := aaddmsg; fsocket := tclientwinsocket.create(integer(not(0))); //fsocket.clienttype := ctnonblocking; //采用阻塞模式 fsocket.clienttype := ctblocking; end; destructor tclientthread.destroy; begin fsocket.free; inherited destroy; end; procedure tclientthread.EXECute; const sizeint = sizeof(integer); sizeblock = sizeof(tdatablock); data: tdatablock = (len: 14; content: 'testpiaoxuesky'); //检查网络异常过程 function isclose(socket, event: cardinal): boolean; var network: twsanetworkevents; begin result := true; fillchar(network, sizeof(network), 0); if wsaenumnetworkevents(fsocket.sockethandle, event, @network) = -1 then exit; { close 消息 } result := ((network.lnetworkevents and fd_close) = fd_close) and (network.ierrorcode[fd_close_bit] <> 0); end; var msg: tmsg; //线程消息 d: tdatablock; //接收数组 timeout, retlen: integer; //超时设置 接收数组大小 event: thandle; //事件句柄 conn: tdatablock ; //发送数组 hadsendconn: boolean; //是否已经登陆 asendmsg: string; //发送字串 count: integer; //发送数组大小 begin try fsocket.open(fhost, fhost, '', 8309); //连接服务端 timeout := 2000; //2秒超时 hadsendconn := false; setsockopt(fsocket.sockethandle, sol_socket, so_rcvtimeo, @timeout, sizeof(timeout)); except exit; end; peekmessage(msg, 0, 0, 0, pm_noremove); event := wsacreateevent; //创建事件句柄 try wsaeventselect(fsocket.sockethandle, event, fd_read or fd_close); while (not terminated) and (fsocket.connected=true) do case msgwaitformultipleobjects(1, event, false, 500, qs_allinput) of //接收网络消息部分 wait_object_0: begin if isclose(fsocket.sockethandle, event) then begin { 'server close' ; } break; end; //初始化接收数组 fillchar(d, sizeblock, 0); retlen := fsocket.receivebuf(d.len, sizeint); if retlen = 0 then break; if retlen <> sizeint then begin continue; end; retlen := fsocket.receivebuf(d.content, d.len); if retlen <> d.len then begin continue; end; //不合规格接收字串丢失 if (copy(d.content,1,4) <> 'succ') and (copy(d.content,1,4) <> 'news') and (copy(d.content,1,4) <> 'hqsx') and (copy(d.content,1,4) <> 'gpsx') and (copy(d.content,1,4) <> 'mmsx') and (copy(d.content,1,4) <> 'gdgg') and (copy(d.content,1,4) <> 'succ') and (copy(d.content,1,4) <> 'lscc') and (copy(d.content,1,4) <> 'ldis') and (copy(d.content,1,4) <> 'lhal') and (copy(d.content,1,4) <> 'oout') and (copy(d.content,1,4) <> 'trys') and (copy(d.content,1,4) <> 'upda') and (copy(d.content,1,4) <> 'test') and (copy(d.content,1,4) <> 'hell') then begin continue; end; //测试字串 if (copy(d.content,1,4)='test') or (copy(d.content,1,4)='hell') then begin //记录最后一个接收到的测试字串事件 lastrecvtest := now(); //writeerrorlog('last rec test message-> '+d.content); continue; end; entercriticalsection(critical1);//进入临界段 //给一个全局变量赋值,因为在主界面接收到wm_getmes消息后需要读取clientrecvmsg内容。 //所以我在这里做了同步操作。 clientrecvmsg := ''; clientrecvmsg := d.content; leavecriticalsection(critical1);//退出临界段 //发送消息刷新界面元素 postmessage(frm_wyclientmain.handle, wm_getmes, 0, 0); //重置事件句柄 wsaresetevent(event); end; wait_object_0 + 1: begin //发送网络消息部分 if peekmessage(msg, 0, 0, 0, pm_remove) then begin case msg.message of wm_user: begin //初始化发送消息字串 asendmsg := clientsendmsg; fillchar(conn, sizeof(conn), 0); conn.len := length(asendmsg); strpcopy(conn.content, asendmsg); count := sizeof(integer) + length(asendmsg); //发送自定义消息 如 登陆,注销等 fsocket.sendbuf((@conn)^, count); end; wm_close: begin //发送客户端正常关闭消息 asendmsg := 'oout$%^&'; fillchar(conn, sizeof(conn), 0); conn.len := length(asendmsg); strpcopy(conn.content, asendmsg); count := sizeof(integer) + length(asendmsg); //正常退出,服务端会对数据库做相应操作 fsocket.sendbuf((@conn)^,count); //退出线程 break; end; end; end; end; wait_timeout: begin //线程启动时发送连接消息 if hadsendconn = false then begin fillchar(conn, sizeof(conn), 0); conn.len := length(connstr); strpcopy(conn.content, connstr); count := sizeof(integer) + length(connstr); fsocket.sendbuf((@conn)^,count); //置已连接标志为真 hadsendconn := true; end; ss := formatdatetime('hh:mm:ss',(now()-lastrecvtest)); if (now()-lastrecvtest)> 6/24*60 then begin break; end; end; else begin wsaresetevent(event); //如果当前事件减去最后接收到测试消息的时间超过6分钟则线程退出 if (now()-lastrecvtest)> 6/24*60 then begin break; end; end; end; finally wsacloseevent(event); try fsocket.close; except on e:exception do writeerrorlog('close sokcet error-> '+e.message); end; end; end; end. |
|
|
|
|