udp传输给说说设计思路?(100分)

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

cuit421

Unregistered / Unconfirmed
GUEST, unregistred user!
问题如下:
有50(可能还多)个客户端向一个服务端发送(udp传输)数据,服务器端收到数据后,首先校验一下正确性,如果校验正确写入数据库,如果写入数据库成功将返回一条确认信息给客户端。
现在问题是如果50个客户端同时向服务端发送数据,那么服务端如何处理最好?会不会因为同时并发传输而导致无法收到一些客户端的数据。如何才能提高处理速度?
请给个设计的建议,最好详细点,不要一句话就完事了。多线程肯定要用了,但是如何让它处理最好?
如果解决了再加分。
 
问题: 服务器端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
===============================================================
&quot;且数据包大小不定,有时大于8K,但是有固定格式&quot;
===============================================================
既然有固定格式,我相信这个格式中,肯定有关于数据包长度的信息,能否把格式贴出来看看?


问题讨论没有结束 ...
 
关注,我下一个程序可能就是你这样的。
 
to weiliu
我要的是udp的协议,你的那些好像不适合我,不过还是感谢,结贴送点小分,请笑纳
 
高手呢?
自己顶一下
 
[:D]我也顶
 
不连续的非相关数据可以,不然用 Tcp
 
是不连续非相关的,不用tcp
 
直接用winsock2.pas中提供的API函数构建一个同步或异步的I/0模式Socket,可以采用select模式等等,
 
感觉总体上可以分两个class完成
一个接收数据包,一个为处理数据包

监听。。
有数据包新启一个接收线程
循环读取数据
if 成功 then 启一个处理线程{处理。。。返回成功。。释放线程。。}
else 读取失败,返回失败。。
释放接收线程

整个过程用短连接,来一数据包个启一线程接收,接收完了就终止掉
 
处理并发难点:缓存数据包,顺序组包。
缓存数据包你可写个类,组包就很容易了。

UDP优点:
易消化無負擔,簡易輕便好攜帶,连接数的限制。

UDP缺點:
上不了抬面、不可靠資料容易被搞丟。

UDP数据包问题:
1.不能保证每个包的先后顺序(因为无连接的,每次传输的路线可能不尽相同),
只有在接收中分析包的顺序, 但可以保证以MTU(最大传输单位[以太网1500左右])
为基准的包传输,不存在边界问题,可完整读取,以便于分析这个包。
如果丢包就是整包,不会将包丢一部分,留一部分。
2.UDP可能有时会丢包,那么本次会话的数据包就不是正确的,在处理超时时,
发现本次会话的数据包超时没有接收完成,就删除该会话数据包。
3.同样将包缓存,再在缓存中分析包,计算CRC, 并取出来处理。

设计UDP数据包: 以下可以理解为一个结构,当然其中还要加其他规则可以更改。

数据流的类型: 1字节(Byte); MSG_DATA or MSG_ENCODE or MSG_TEXT
数据校验码: 2字节(WORD); CRC校验
流水号: 4字节(Int);
总包数: 2字节(WORD) ; 本次会话总包数
当前包ID: 2字节(WORD); 本次传输的包数
数据段: N字节,根据实际情况来定。
前11字节为包头,后面的字节为真实数据;
 
要写个UDP/TCP 高效安全好的通讯程序不容易; 里面的设计规则很多很多。
1. 光上面还是其中一部分,数据包缓冲之前,处理大量并发,要在接收线程中做,
数据包队列,队列这个类在bbs上都有,因为你是并发,所以队列很重要不然丢包严重,
再在另一个线程中处理队列中的数据包放入缓冲,
缓中中的包才是一组完整的一次通信会话。
在通过缓中的包调度给应用层处理并返回。
2.设计体系,最好分层次,最底层UDP通信协义做基本的通信,中间做CRC,队列,缓冲,应用层做些简单逻辑处理,用户交互等。
 
没人回答,自己也解决的差不多了,现在dfw上真正愿意为别人回答有难度问题的人少了,都搞成收费控件了,还不如看看以前的dfw们回答的帖子有用,结贴了。
 
后退
顶部