问题: 服务器端ServerSocket要同时接收多处ClientSocket端的数据包,且数据包大小不定,大于8K ( 积分: 200 )
分类: Internet/TCPIP
来自: eachbuilder, 时间: 2004-07-31 16:07:00, ID: 2741509
服务器端ServerSocket要同时接收多处ClientSocket端的数据包,且数据包大小不定,有时大于8K,但是有固定格式,发现用ServerSocket接收的时候它分多次接收的(次数不定),我想把数据拼起来,但是怎么处理是不是同一地方的数据?怎么知道一个地方的数据已经收完了?本来包格式里是有地址信息的,但是分多次就有可能某半条包没有地址信息了。或者有没有办法一次收完一个地方的数据?请高手帮忙!!
来自: hardware007, 时间: 2004-08-02 9:19:26, ID: 2743268
加标识
来自: 雪人Snowman, 时间: 2004-08-02 9:38:36, ID: 2743326
数据包8k过大了。
你把数据包尺寸定的小些,让server能一次接收一个包,然后每个包里指定地址id 与 数据pos,肯定没问题的,以前我做过
来自: eachbuilder, 时间: 2004-08-02 9:49:47, ID: 2743358
发送程序不是我做的,人家已经做好了,不好改的,而且现在还涉及多处同时发,我这边要同时收的问题
来自: slicker, 时间: 2004-08-02 10:13:46, ID: 2743426
ServerSocket 对于每个连接在服务器端建立单独的 ClientSocket,然后通过这个服务器端的 ClientSocket 和客户端的 ClientSocket 通讯
TCP是面向连接的协议,连接建立后,只需要关注传送的数据即可,不会出现在一个连接上出现其它连接的数据
数据包既然有固定的格式,那么也应该有开始、结束标志,或者数据包大小的信息,根据这些信息判断接受的数据是否是同一个数据包中的
调用 ClientSocket 的 WaitForData 方法,可以判断端口上是否有数据到达
来自: 雪人Snowman, 时间: 2004-08-02 10:39:59, ID: 2743501
发送部分不能动的话........可以这么办:
每个地址给你发数据的时候首先提交一句 地址id,然后你临时保存一下地址id与其ip地址的对应关系,然后你就根据数据包里的ip来判断是来自什么地址的。如果不同地址里有同一局域网内给你发的两个以上不同的地址信息(比如外地一公司的开发部与财务部算两个地址的话),连同port也记录来区别。
tcp/ip协议的话,程序相对就比较简单了,如果是udp,嘿嘿.......
来自: eachbuilder, 时间: 2004-08-02 11:17:53, ID: 2743610
to slicker:可否来点代码
来自: eachbuilder, 时间: 2004-08-02 11:19:20, ID: 2743617
“每个地址给你发数据的时候首先提交一句 地址id”,发送程序人家已经做好了呀,没法改了,人都跑了,么源代码
来自: delphilxh, 时间: 2004-08-02 11:29:36, ID: 2743647
你在接收里处理呀,每个客户对应一个缓冲区不就可以了
来自: eachbuilder, 时间: 2004-08-02 11:40:42, ID: 2743681
那怎么处理是哪个客户啊?怎么知道哪个客户已经发完数据了?
来自: slicker, 时间: 2004-08-02 11:47:48, ID: 2743704
能否确定是TCP/IP连接?
如果确定的话,就很紧简单了
来自: eachbuilder, 时间: 2004-08-02 12:09:13, ID: 2743776
是TCP
来自: hryyx, 时间: 2004-08-02 13:04:25, ID: 2743894
对方IP地址还用人家告诉你吗?使用下面的语句应该能获得
ServerSocket1.Socket.Connections[0].RemoteHost
来自: eachbuilder, 时间: 2004-08-02 13:47:04, ID: 2743996
每个客户端的IP是相同的
来自: slicker, 时间: 2004-08-02 13:57:13, ID: 2744017
TCP/IP是面向连接的,通过过程中,双方的连接必须维持,所以不用担心一个 ClientSocket 会出现其他客户端的数据的情况
建议在服务器端采用 TTcpServer 控件,Delphi 原来提供的 TServerSocket 和 TClientSocket 控件并不好使用,在 Delphi6 就已经用 TTcpServer/TTcpClient 代替了
在服务器端的处理,集中在 TTcpServer 的 OnAccept 事件中处理(对于ServerSocket也一样)
procedure OnAccept(Sender: TObject; ClientSocket: TCustomIpClient);
var Buf : array[0..1023] of Char;
ilSize : Integer;
begin
// 传递进来的ClientSocket,即服务器建立的和客户端通信的 TTcpClient
// ClientSocket 有 TTcpServer 负责建立和释放,此处直接使用即可
// 连接的客户端的地址信息,通过 ClientSocket 的属性和方法即可得到
while ClientSocket.WaitForData do
begin
ilSize := ClientSocket.ReceiveBuf(Buf, 1024);
if ilSize = -1 then
// 端口错误, 通过提供 TSocketErrorEvent 错误事件处理
else
begin
// 和上一次读取的 Buf 组合
if ilSize < 1024 then
begin
// 读取的字节小于缓冲大小,没有更多的数据,可以结束
// 也可以通过数据包中的控制信息判断
end
end
end;
end;
不用担心多个客户端的情况,TTcpServer 通过线程控制,为每个客户端连接建立一个单独的线程处理,当然,你要注意对全局变量的保护
TServerSocket 的处理方法和 TTcpServer 类似
来自: flybird00000, 时间: 2004-08-02 14:05:51, ID: 2744030
同意slicker看法你受到数据之后可以在那个连街上直接返回数据。
来自: eachbuilder, 时间: 2004-08-02 14:25:54, ID: 2744079
谢谢slicker
“和上一次读取的 Buf 组合”,这个方法很好,但是我肯定要一个客户端建立一个buf,问题是我怎么区分不同的客户端,客户端IP什么的没有用的,都一样。数据包里本来有客户端信息,但是多次接收,有的包里就没有了。我现在用的是 TServerSocket控件,以上代码是写在OnAccept事件还是OnClientConnect
来自: slicker, 时间: 2004-08-02 15:17:20, ID: 2744206
通过LocalPort区分,连接的 LocalPort 肯定是唯一的!
我早就不用 TServerSocket 了,如果使用 TTcpServer,只有 OnAccept
至于 TServerSocket,自己试一试吧
来自: qxb0104, 时间: 2004-08-02 17:42:33, ID: 2744564
长连接还是短连接
来自: qxb0104, 时间: 2004-08-02 17:45:05, ID: 2744569
在一次SOCKET连接断开之前,SOCKET是固定的,通过它作为标识,标明是哪个客户端发的数据,在DELPHI中好像是SOCKET。HANDLE
来自: fu_qi_ming, 时间: 2004-08-02 17:49:35, ID: 2744580
socket就是标示,一个连接一个,肯定不一样。
用socket的值判断就行。
来自: loadymf, 时间: 2004-08-04 0:17:38, ID: 2747146
Sock
来自: painboy, 时间: 2004-08-04 16:24:56, ID: 2748370
楼主,真不知道怎样说你才好。
现在的情况是不是,每个客户可以发起多个连接到服务器上,并同时传送数据?
如果是,则再说。
好的程序设计应该是:
如果采用长连接,那数据包不能太大,确保每个数据包能够一次发送、接收完毕;(每个数据包是独立的,有意思的)
如果采用短连接,则数据包大小随意,反正客户断开就表示数据发送,亦即接收完毕。(每个数据块是上下关联的,不能独立解释)
如果你的TServerSocket用的是线程阻塞模式,那各个连接的数据接收方面是不会乱的,因为每个线程独立。
但你现在碰到的是,数据包太大了,在连接的有效期内(是不是长连接?),你就想检查(合并?)接收到的数据块,并试图解释它。
注:这里, 数据包 >= 数据块
正是这种糟糕的数据规划,把原本很简单的问题变复杂了。你说的不是不能实现,但要在发送端程序里加很多状态,接收端程序里做状态检查。有必要吗?你还说没有源程序,就更别谈了。
来自: xujunjie, 时间: 2004-08-05 13:47:18, ID: 2749872
TCP协议本身决定了在接收时会出现数据包粘连现象(一次接收多个包或一个包需多次接收),处理这个问题有一个办法:在发送每个数据包前加上包的长度,接收端按这个长度来接收数据,举例如下:
const
BUFSIZE = 4096;
var
RecvLen, PackSize, ReadCount, C: Integer;
Buf: array[0..BUFSIZE - 1] of char;
Stream: TStream;
begin
RecvLen:= Socket.ReceiveLength;
//处理一次接收多个包的情况
while RecvLen > 0 do
begin
Stream:= TMemoryStream.Create;
try
Socket.ReceiveBuf(PackSize, SizeOf(Integer)); //包的长度
ReadCount:= 0;
//处理包太大,需多次接收的情况
while ReadCount < PackSize do
begin
C:= Socket.ReceiveBuf(Buf, BUFSIZE);
if C = -1 then Continue; //网速慢时接收不到数据
Stream.Write(Buf, C);
Inc(ReadCount, C);
end;
//Todo:接收到了一个完整的数据包,这里写自己的处理过程
finally
Stream.Free;
end;
Dec(RecvLen, ReadCount);
end;
end;
来自: xujunjie, 时间: 2004-08-05 13:46:49, ID: 2749878
TCP包没有8K的限制,放心使用大缓冲区好了:)
来自: xujunjie, 时间: 2004-08-05 13:53:32, ID: 2749903
TCP完全不用考虑拆包和组装包,因为是流的方式,按顺序读就是了。只有大的UDP包才需考虑。
来自: painboy, 时间: 2004-08-06 14:53:26, ID: 2751932
To xujunjie兄:
楼主好象说他没有发送端的程序,也就是,发送时,不会先发送包的长度给接收方。所以你说的
Socket.ReceiveBuf(PackSize, SizeOf(Integer)); //包的长度
是不可能的。因为在发送方,程序没有:
Socket.SendBuf(PackSize,SizeOf(Integer));
而是直接的:
Socket.SendBuf(DataBuf,BufferLen);
这样的程序真是…………
来自: xujunjie, 时间: 2004-08-06 15:39:11, ID: 2752048
我上面的代码并不是一个完整的实例,只是说明一下原理而已,实际代码肯定不会这么简单吧,而且描述部分已经说清楚了发送端需先发送长度,没必要把客户端的代码也写出来呀
来自: painboy, 时间: 2004-08-06 16:06:47, ID: 2752067
To xujunjie兄:
楼主的意思应该是他没办法改客户端的程序………
To 楼主:
既然你的数据有固定格式,那在你的接收端(服务器)程序里设一个标志,每接收一个数据包,就检查它的格式。
假定你的TServerSocket用的还是线程阻塞模式,如下:
const
BUFSIZE = 1024;
var
RecvLen , nCount : Integer;
Buf: array[0..BUFSIZE - 1] of char;
Stream: TStream;
TheStream := TWinSocketStream;
begin
......
TheStream := TWinSocketStream.Create(ClientSocket,120000);
nCount := 0;
while (not Terminated) and (CleintSocket.Connected) do begin
if TheStream.WaitForData(10) then begin
RecvLen := TheStream.Read(Buf, BUFSIZE);
if Buf是整个数据包的第一片 then begin //这里,根据你的数据格式,对每片数据进行检查
Inc(nCount);
if nCount>1 then begin //之前曾接收过数据,则
...... //上一轮的数据已经接收完毕,放在Stream里,你处理啦
Stream.Free; //释放,如要保存,在上一步要做好
nCount := 1; //重置计数器(不是0啊,因为已收到一片数据了)
end;
Stream := TStream.Create; //新一轮接收开始
end;
Stream.Write(Buf, RecvLen); //写入接收的数据片
end;
end;
......
end;
来自: xujunjie, 时间: 2004-08-06 16:03:04, ID: 2752107
呵呵,我没看到楼主的客户端不能变,说来说去还是不清楚,把数据包格式贴出来才知道怎样处理呀,楼主让大家这样猜来猜怎么行呢?
来自: smokingroom, 时间: 2004-08-10 14:32:49, ID: 2757603
===============================================================
"且数据包大小不定,有时大于8K,但是有固定格式"
===============================================================
既然有固定格式,我相信这个格式中,肯定有关于数据包长度的信息,能否把格式贴出来看看?
问题讨论没有结束 ...