关于多线程TCP通讯 (100分)

  • 主题发起人 主题发起人 cjsam
  • 开始时间 开始时间
C

cjsam

Unregistered / Unconfirmed
GUEST, unregistred user!
unit TsocketThread_p;

interface

uses
Classes,Sysutils,winsock,Messages,Dialogs;
const
WM_SOCK = WM_USER + 1;
type
TTSocketThread = class(TThread)
private
Fid:string;
FIp:string;
FPort:string;
sock: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn;
path:string;//记录该通讯日志的路径
protected
procedure Execute; override;
Procedure CreateSocket;
procedure ReadData(var Message: TMessage);message WM_SOCK;
procedure senddate;
public
Constructor create(Ip,port,id:string;);
destructor Destroy; override;
end;

implementation

{ TTSocketThread }
{参数:
IP:远程机器IP
PORT:远程机器PORT
ID:一个线程建立通讯对应的ID。
}

constructor TTSocketThread.create(ip,port,id:string);
var
s:TDateTime;
begin
FIp:=ip;
FPort:=port;
Fid:=id;
CreateSocket;

inherited create(false);
end;
Procedure TTSocketThread.CreateSocket;
var
TempWSAData: TWSAData;
err:integer;
begin
path:='/'+Fid+'_comm.log';
addr.sin_family:=PF_INET;
addr.sin_port:=htons(strtoint(FPort));
addr.sin_addr.S_addr:=inet_addr(pchar(FIp));
err:=WSASTARTUP($101,TempWSAData);
IF err=0 THEN
BEGIN
WriteLog(now,'编号为:'+Fid+' 的SOCKET初始化成功',path);
sock:=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
IF SOCK=INVALID_SOCKET THEN
WriteLog(now,'编号为:'+Fid+' 的SOCKET初始化失败',path)
else
begin
WriteLog(now,'编号为:'+Fid+' 对应的线程SOCKET创建成功',path);
err:=CONNECT(sock,addr,sizeof(addr));

if err=socket_error then
begin
WriteLog(now,'编号为:'+Fid+' 的SOCKET连接通讯主机失败!',path);
err:=closesocket(sock);
if err=0 then
WriteLog(now,'编号为:'+Fid+' 的对应SOCKET释放成功!',path);
end
else
begin
WriteLog(now,'编号为:'+Fid+' 的对应SOCKET连接通讯主机成功!',path);
exit;
end;
end;
WSAcleanup;
end;
///********************************************
WSAAsyncSelect(sock, handle, WM_SOCK, FD_READ );
//将消息帮定,但是因为没有窗体,第二个参数到底怎样写呀。
//它的值取谁的 HANDLE
//*******************************************



end;

destructor TTSocketThread.Destroy;
begin
WriteLog(now,'ID:'+Ftelid+'通讯结束!',path);
inherited;
end;

procedure TTSocketThread.Execute;
var
len:integer;
begin
//FreeOnTerminate:=true;

senddate;

end;

procedure TTSocketThread.ReadData(var Message: TMessage);
var
flen: integer;
Event: word;
RecvBuff:array [0..1024] of char;
RecvS:string;
begin
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Port := htons(strtoint(Fport));
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
recvfrom(sock,RecvBuff,sizeof(RecvBuff),0,FSockAddrIn,flen);
end;
end;

procedure TTSocketThread.senddate;
var
ret,len:integer;
s:string;
psend:pchar;
begin
s:='01,'+Fid+';';
len:=length(s);
psend:=stralloc(len);
Strpcopy(Psend,S);
ret:=send(sock,psend^,len,0);
WriteLog(now,s,path);
if ret=SOCKET_ERROR then
WriteLog(now,'发送 '+s+'失败',path);
end;
end.
请大家帮我看一下,我程序有什么问题?能够发送,服务端接受也正确。但是这个线程不能拦截服务端发送来的消息。收不到。
我想问下大家,创建SOCKET的时候,
addr.sin_family:=PF_INET;
addr.sin_port:=htons(strtoint(FPort));
addr.sin_addr.S_addr:=inet_addr(pchar(FIp));
err:=WSASTARTUP($101,TempWSAData);
这个里面对应的IP,PORT是远程服务端的IP,PORT吧?
那我线程中创建的SOCKET的自己 的IP,PORT是在那设置?我不太清楚API创建SOCKET的关系。谢谢。
 
请大家帮忙看看呀
 
我上面问的问题主要就是:
如何将我自己定义的客户端接受服务端的数据来的消息绑定到我的SOCK上去??
///********************************************
WSAAsyncSelect(sock, handle, WM_SOCK, FD_READ );
//将消息帮定,但是因为没有窗体,第二个参数到底怎样写呀。
//它的值取谁的 HANDLE
//*******************************************

或者是:

a:=WSACreateEvent();//a定义成什么类型呀?
WSAEventSelect(sock,a,wm_sock,fd_read);
具体到底怎样绑定呀?100分是不是太少了,大家都没兴趣?

 
1.在类中申明一个成员变量:
FWindow: THandle;

2.在类中加一个方法:
procedure WindowMethod(var Message: TMessage);

3.在Create方法中加:
FWindow := AllocateHWnd(WindowMethod);

4.在Destroy中加:
DeallocateHWnd(FWindow);

5.写方法:
procedure TTSocketThread.WindowMethod(var Message: TMessage);
begin
if Msg = WM_SOCK then
ReadData(Message)
else
Msg.Result := DefWindowProc(FWindow, Msg, wParam, lParam);
end;

6.去掉ReadData申明后面的 :WM_SOCK

7.将WSAAsyncSelect写成:
WSAAsyncSelect(sock, FWindow, WM_SOCK, FD_READ );

 
每一个TCP连接在connect后,serversock都有一个onclientconnect事件,你就用当前的就可以了。是索引来着。

或者你建立一个记录集,每一个连接都保存他的handle值,就可以了。
 
coao:
用WinSocket API写,没有OnClientConnect!!
 
apw:

AllocateHWnd(WindowMethod);
DeallocateHWnd(FWindow);
在什么里面定义呀?
 
AllocateHWnd和DeallocateHWnd是Win API函数,在Forms.pas单元中.

constructor TTSocketThread.create(ip,port,id:string);
var
s:TDateTime;
begin
FIp:=ip;
FPort:=port;
Fid:=id;

[red] FWindow := AllocateHWnd(WindowMethod);[/red]
CreateSocket;

inherited create(false);
end;

destructor TTSocketThread.Destroy;
begin
[red]DeallocateHWnd(FWindow);[/red]
WriteLog(now,'ID:'+Ftelid+'通讯结束!',path);
inherited;
end;

 
WindowMethod应该是这样吧。
procedure TTSocketThread.WindowMethod(var Message: TMessage);
begin
if Message.Msg=WM_SOCK then
ReadData(Message)
else
Message.Msg := DefWindowProc(FWindow, Message.Msg, Message.wParam, Message.lParam);
end;

APW
好象还是拦截不到哪个事件。会不会是其他那还有问题呀。
 
多人接受答案了。
 
后退
顶部