一个在现线程中的通讯问题?(100分)

  • 主题发起人 主题发起人 moses1999
  • 开始时间 开始时间
M

moses1999

Unregistered / Unconfirmed
GUEST, unregistred user!
就是我写了一个线程,在里面创建了一个clientSOCKET的连接,
还构造了一个消息循环,每当socketSERVER端给我返回一个确认包时
我就向MEM控件根据socketserver编号写一个成功信息,
可是当我在循环中连续启动两个线程发送信息的时候,发送成功后
我向界面中的MEM控件中会写入大于两条的成功信息,而且有的编号显示了两条以上的成功信息
有的socketserver编号的成功信息根本就没有被写入,总体写入的信息的条数都大于所下发的socketserver数
不知道我这段程序哪里出了问题?请高手给予指点。

//该部分为在循环中执行,循环条件为socketserver 编号的数量
with adoqry.recordcount<>0 do
begin
Tmpaddr:=adoqry.fields[0].asstring;
recive_type(11);//取得传送文件的类型
recive_name(readername);//取得要传送的读卡器描述
recive_pcmid(Treadid);//取得要传送的socketserver的编号
DTtext:='DT'+hexstrtobin(tmpcom,1)+hexstrtobin(TmpID,6)+TmpStr;
CTcmd:=GreCommand(CMD_DLCCRFILE,length(DTtext));
Receive_comm(CTcmd);//调用线程模块提供接口传送命令包
Receive_data(DTtext);//调用线程模块提供接口传数据包
Recive_addr(Tmpaddr);//调用线程模块提供接口传ip地址
CcrSock:=TCsocket.Create(false);//创建并执行线程;
adoqry.next;
end;
//该部分为线程的实现部分
{********************************************************}
{* 该模块为为通信服务的线程模块,在该线程中动态的创建 *}
{* SOCKET对象,并且将在其他模块达好包的配置文件传入进来 *}
{* 本模块提供对外的接口过程为: *}
{* Receive_comm(ReccmdStr:string):接受命令包字符串 *}
{* Receive_data(RecDataStr:string):接受数据抱字符串 *}
{* Recive_addr(RecAddr:string):接受ip地址 *}
{* 在打好包后调用这两个过程传递进来,调用线程只需要在调用*}
{* 时声明一个该线程的对象,然后就将他创建出来 *}
{********************************************************}
unit ThreadSocket;

interface

uses
Classes,ScktComp,sysutils,Graphics,windows,trans,unitmain,messages,ExtCtrls,forms;
type
TCsocket = class(TThread)
private
cskccr:Tclientsocket;
{ Private declarations }
protected
procedure write_canves;
procedure doconnect(Sender: TObject;Socket: TCustomWinSocket);
procedure doError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure doRead(Sender: TObject;Socket: TCustomWinSocket);
procedure Execute; override;
public
constructor Create(createsuspended:boolean);
end;
var
CmdStr:string;
DataStr:string;
AddrStr:string;
typeid:integer;
msg:tagMSG;
net_str:string;//网络状态提示字符串;
readerserial:string;//读卡器序列号字符串
time_str:integer;
pcmname:string;
PrintStr:string;

function labfaile(typeid:integer;net_str:string):string;//提示下载失败
function labsucc(typeid:integer):string;//提示下载成功
procedure Receive_comm(ReccmdStr:string); //接收命令字符串过程
procedure Receive_data(RecDataStr:string);//接收数据字符串过程
procedure Recive_addr(RecAddr:string);//接收IP地址字符串过程
procedure recive_type(rectype:integer);//接收下载项目类型
procedure recive_name(reader_name:string);//接收读卡器序名称
procedure recive_pcmid(pcm_ID:integer);//取得PCM的ID
procedure net_messages(net_code:integer);//网络状况信息提示;

implementation
constructor TCsocket.Create(createsuspended:boolean);
begin
inherited Create(false);

cskCCR:=Tclientsocket.Create(nil);
cskCCR.Address:=AddrStr;
cskCCR.Port:=8001;
cskCCR.ClientType:=ctNonBlocking;
cskCCR.OnConnect:=doconnect;
cskCCR.OnError:=doError;
cskCCR.OnRead :=doread;
synchronize(write_canves);
freeonterminate:=true;
end;
procedure TCsocket.write_canves;
var
tmp:string;
begin
tmp:=PrintStr;

Frmtrans.Mem.Lines.Add(tmp);
end;
procedure Receive_comm(ReccmdStr:string); //接收命令字符串
begin
CmdStr:=ReccmdStr;
end;

procedure Receive_data(RecDataStr:string);//接收数据字符串
begin
DataStr:=RecDataStr;
end;

procedure Recive_addr(RecAddr:string);//接收IP地址
begin
AddrStr:=trim(RecAddr);
end;

procedure recive_type(rectype:integer);//接收下载项目类型
begin
typeid:=rectype;
end;

procedure recive_pcmid(pcm_id:integer);//接收clientserver的编号
begin
pcmname:=inttostr(pcm_id);
end;

procedure recive_name(reader_name:string);//接收读卡器的描述
begin
readerserial:=reader_name;
end;

{连接事件}
procedure TCsocket.doconnect(Sender: TObject;Socket: TCustomWinSocket);
begin
Socket.SendText(CmdStr);//命令包
Socket.SendText(DataStr);//数据抱
end;
{错误处理事件}
procedure TCsocket.doError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
net_messages(errorcode);
PrintStr:=labfaile(typeid,net_str);
synchronize(write_canves);
errorcode:=0;

Socket.Close;
PostThreadMessage(0,$0012,0,0);

end;
{读取文本事件}
procedure TCsocket.doRead(Sender: TObject;Socket: TCustomWinSocket);
var
FStr:string;
begin
FStr:=Socket.ReceiveText;
if Copy(Fstr,1,2)='DT' then
begin

PrintStr:=labsucc(typeid);
synchronize(write_canves);
Socket.Close;
PostThreadMessage(0,$0012,0,0);
end;
end;
procedure TCsocket.Execute;
begin
cskCCR.Active:=true;
while (GetMessage(msg,0,0,0)) do
begin
dispatchMessage(msg);
end;
cskCCR.Free;
Terminate;

end;

function labsucc(typeid:integer):string;
var
i:integer;
begin
i:=typeid;
case i of
1://时间组
begin
result:='向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'时间组成功';

end;
2://黑名单
begin
result:='向'+pcmname+'号PCM'+'下发黑名单成功';

end;
3://白名单
begin
result:='向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'白名单成功';

end;
end;
end;
function labfaile(typeid:integer;net_str:string):string;
var
i:integer;
netstr:string;
begin
i:=typeid;
case i of
1://时间组
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'时间组失败';
end;
2://黑名单
begin
result:=netstr+','+'向'+pcmname+'号PCM'+'下发黑名单失败';
end;
3://白名单
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'白名单失败';
end;
4://时间组对应成员组
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'时间组对应成员组失败';
end;
9: //双卡开门
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'双卡开门失败';
end;
10://门禁机优先序列
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'门禁机优先序列失败';
end;
11:// 门禁机配置文件
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'门禁机配置文件失败';
end;
14://加班名单
begin
result:=netstr+' '+'向'+pcmname+'号PCM下发'+trim(readerserial)+'的'+'下发加班名单失败';
end;
end;
end;
procedure net_messages(net_code:integer);
begin
case net_code of
10049:begin
net_str:='设置地址失败';
end;
10050:begin
net_str:='网络关闭';
end;
10051:begin
net_str:='网络不可达';
end;
10057:begin
net_str:='SOCKET未连接';
end;
10058:begin
net_str:='SOCKET已经关闭';
end;
10060:begin
net_str:='连接超时';
end;
10061:begin
net_str:='连接被拒绝';
end;
10064:begin
net_str:='主机已经关机';
end;
10065:begin
net_str:=' 找不到路由';
end;
10067:begin
net_str:='进程太多';
end;
11001:begin
net_str:='找不到主机';
end
else
net_str:='其他原因导致网络错误';
end;
end;
end.
 
看不出问题所在帮你提前
 
两个线程监测的端口一样吗,如果大家同时读怎么办??不出错,或出现两次那才叫怪呢??
而且在线称种对memo的访问本身就是不安全的,我想你应该对线程进行同步。试试这样:
定义一全局变量 ReadLock=CreateMutex("abcdefgh",nil);
在线程中读或些的时候 先 WaitForSingleObject(ReadLock,1000);只有在该函数返回
wait_object_0 时,再动作。大概是这样吧,自己看API帮助吧
 
发个完整的DEMO给我,我帮你调试
这样看太累了。
gdcqs14@21cn.com
 
to lvxq
我这样写的,可是不行 能给瞧一下么?最好在我的代码上改一下,谢谢
procedure TCsocket.doconnect(Sender: TObject;Socket: TCustomWinSocket);
begin
Socket.SendText(CmdStr);//命令包
Socket.SendText(DataStr);//数据抱
end;
{错误处理事件}
procedure TCsocket.doError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
net_messages(errorcode);
PrintStr:=labfaile(typeid,net_str);
synchronize(write_canves);
cskCCR.Close;
errorcode:=0;
PostThreadMessage(0,$0012,0,0);
closehandle(hmutex);

end;
{读取文本事件}
procedure TCsocket.doRead(Sender: TObject;Socket: TCustomWinSocket);
var
FStr:string;
begin
FStr:=Socket.ReceiveText;
if Copy(Fstr,1,2)='DT' then
begin
PrintStr:=labsucc(typeid);
synchronize(write_canves);
cskCCR.Close;
PostThreadMessage(0,$0012,0,0);
closehandle(hmutex);
end;
end;
procedure TCsocket.Execute;
begin
freeonterminate:=true;
cskCCR:=Tclientsocket.Create(nil);
if waitforsingleobject(hmutex,infinite)=wait_object_0 then
begin
cskCCR.Address:=AddrStr;
cskCCR.Port:=8001;
cskCCR.ClientType:=ctNonBlocking;
cskCCR.OnConnect:=doconnect;
cskCCR.OnError:=doError;
cskCCR.OnRead :=doread;
cskCCR.Active:=true;
while (GetMessage(msg,0,0,0)) do
begin
dispatchMessage(msg);
end;
cskCCR.Free;
end;
end;
 
对不起,我得给小日本干活,没法给你改,你大体上是正确的。除了:
1。我不知道你在哪里创建了,当然可能在别的地方;
2。调用此函数的目的是为了同步,所以建议在DoRead/DoWrite事件中使用,或在此
之前使用,比如:
var
myret: DWORD;
......
myret:=WaitForSingleObject(lockhandle,1000);//lockhandle as before
case myret of
case Wait_OBJECT_0 :
begin
DoRead( .......) ;
//call here before WinSocket begin read;
end;
end;
3. 很抱歉,前面没仔细看你的代码,因为你已经加了同步函数了,就是
synchronize(write_canves);
不过,照我的观点,你使用的位置还是有点问题。 (既然,你前面没反驳,说明你
自己也不是很确切理解代码的意思,我就神侃了,呵呵。。。。。)



 
多人接受答案了。
 

Similar threads

后退
顶部