关于Socket.Receive()与Send()的常见问题

来源:互联网 发布:数据库的逻辑模型图 编辑:程序博客网 时间:2024/06/06 09:53

Socket.Receive 方法 (Byte(), Int32, Int32, SocketFlags)

使用指定的 SocketFlags,从绑定的Socket 接收指定的字节数,存入接收缓冲区的指定偏移量位置。

public int Receive(byte[] buffer,int offset,int size,SocketFlags socketFlags)

参数
buffer
类型:System.Byte()
Byte 类型的数组,它是存储接收到的数据的位置。
offset
类型:System.Int32
buffer 中存储所接收数据的位置。
size
类型:System.Int32
要接收的字节数。
socketFlags
类型:System.Net.Sockets.SocketFlags
SocketFlags 值的按位组合。
返回值
类型:System.Int32
接收到的字节数。

(以上部分来自MSDN)
接下来我的经验总结:

1,Socket实际接收到的字节数与预期想要接收字节数

我们从上面的返回值可以清晰的知道,虽然我们给Buffer定义了一个长度和要接收到的size,但是Socket接收到的字节数(即返回值)并不一定等于Size

所以我们在做这个的时候,需要判断,实际接收到的字节数是否等于要接收的字节数!这个很重要。

 //定义接收数据的缓存 byte[] body = new byte[1024]; //第一次接收的实际数据 flag int flag = socket.Receive(body, 0, body.Length, SocketFlags.None); //如果没有接收到定长的数据,循环接收 while(flag != body.Length) {    flag += socket.Receive(body, flag, body.Length - flag, SocketFlags.None); }

因此,Socket接收数据的过程应该是这样的!

2,服务器发送多次,客户端一次接收的问题。

当然在实际的编程中很少这么干的,但是我这么写是想说明一个问题:假如客户端想一次接收服务器多次发送过来的数据,客户端定义缓存body的长度等于服务端多次发送的数据长度和,客户端在服务器发送完成后开始一次接收,客户端肯定能接收到服务器发送过来的所有数据,不会只接收服务器发送过来的部分数据。

我的叙述很烂!打个比方,假如服务器分三次分别发送“Hell”,“0”,“World”。这样客户端一定能接受到“HelloWorld”。而不是“Hell”或者其他什么的东西。

3,Socket.Send()

Send 将数据同步发送到 Connect 或 Accept 方法中指定的远程主机,并返回成功发送的字节数。Send 对面向连接的协议和无连接协议均适用。

此重载要求一个缓冲区来包含要发送的数据。SocketFlags 的默认值为 0,缓冲区偏移量的默认值为 0,发送字节数的默认值为缓冲区的大小。

如果您使用的是无连接协议,则必须先调用 Connect 才能调用此方法,否则 Send 将引发 SocketException。

如果您使用的面向连接的协议,则必须使用 Connect 建立远程主机连接,或者使用 Accept 接受传入的连接。

如果您使用的是无连接协议,并且打算将数据发送到若干不同的主机,则应使用 SendTo 方法。如果不使用 SendTo 方法,则每次调用 Send 之前必须调用 Connect。即使已经用 Connect 建立了默认远程主机,也可以使用 SendTo。通过另外调用 Connect,也可以在调用 Send 之前更改默认远程主机。

如果您使用的是面向连接的协议,则除非使用 Socket.SendTimeout 设置了超时值,否则,Send 将一直处于阻止状态,直到发送完缓冲区中的所有字节。如果超过超时值,Send 调用将引发 SocketException。在非阻止模式下,Send 可能会成功完成,即使它发送的字节数小于缓冲区中的字节数。应由您的应用程序负责跟踪已发送的字节数并重试操作,直到应用程序发送了缓冲区中的字节数为止。不能保证发送的数据会立即出现在网络上。为提高网络效率,基础系统可能会延迟传输,直到收集了足够多的传出数据后才开始发送。Send 方法的成功完成意味着基础系统有空间来缓冲用于网络发送的数据。

 4,总结

Send()方法只是将发送缓存的数据压入基础系统的控件中。而Receive()方法只是数据通过网络到达机器后,从基础系统的空间中读取数据。