C# Socket的Send,beginsend等方法的区别

经过一番研究,终于可以确认,.net socket的beginSend和beginReceive用的是完成端口。(windows 98上不是,因为98没有这样的机制)。如果微软没有撒谎的话。

发送大量数据时,Socket.BeginSend和Socket.Send的速度是有差别的。在局域网里面,这种差别表现不明显。但是在一个高延迟的网络中,差别就很大。

Socket.Send方法是可靠的。但是Send的时候,是等到缓冲区发出的包被确认以后才继续发送后续的包。所以,即使网络的带宽很大,但是如果网络延迟高,发送速度也会很慢。

Socket.BeginSend(异步)是把要发送的数据直接写入缓冲区,然后调用返回。BeginSend发送的时候,并不能确定发送是否成功。BeginSend的时候,指定了一个回调方法,发送成功后,系统会调用这个回调方法。在回调方法中,可以通过EndSend来检查实际发送的字节数。

虽然msdn中没有说明,但是实际上在EndSend中返回的字节数总是等于发送的字节数,或者抛出异常。

BeginSend的发送速度,可以占用全部的网络带宽。而Send的速度受网络延时的影响很大。在网络延迟高的网络中,可能每秒只有几K的速度。实际上,这个速度大致等于系统发送时的每个ip包的大小除以网络延迟的秒数。

完成端口使用的要点,就是减少系统中线程的数量。

所以,不要以为用了BeginSend就一定可以提高系统的负载能力。主要还是在于减少系统中工作的线程数量。所以,尽量不要在线程中使用阻塞的方法。

Socket.BeginReceive方法和Socket.Receive方法,对接受的速度没有影响。因为根据tcp协议,既然这个包已经到了应用 层,那么肯定是已经实际收到了。用BeginReceive的优势是在于可以不阻塞线程,从而减少系统中工作的线程。对于负载量不大的系统,用 Receive就可以了。Receive的逻辑比较简单。但是需要记住一点,Receive时返回的字节数,不一定等于要求读取的字节数。系统只是在数据 包到达时,尽可能的读取要求的字节数。

.net的Socket Api其实是对系统Socket Api的封装。所以以上的说法同样适用于winsock。但是由于BeginSend方法封装了完成端口,所以可以在获得高性能的同时,少了很多麻烦。对于网络的编程,是非常美妙的一件事情。

BeginSend需要注意的是,一定要控制发送的速度。否则,这个连接一定会因为系统缓冲区满而抛出异常。控制速度的办法就是在发送时计算发送的包数 量,在EndSend的时候计算发送成功的包数量。在发送之前,检查未发送的包数量,如果小于预设值则发送,否则暂停。这个地方会阻塞线程,所以也不是最 好的方法,比较好的办法,是自己做个发送缓冲队列。然后用一个专门的线程来处理发送。这样,只要用很少的线程,就可以处理发送。虽然BeginSend用 了完成端口,但是如果在系统中有大量被阻塞的线程,那就违背了完成端口的本意。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C# 中的 Socket 类提供了底层的网络编程接口,但使用起来相对较为繁琐,因此可以进行封装,以便更方便地使用。以下是一个简单的 C# Socket 封装示例: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; public class SocketClient { private Socket _socket; private byte[] _buffer = new byte[1024]; public SocketClient(string ipAddress, int port) { IPAddress ip = IPAddress.Parse(ipAddress); IPEndPoint remoteEP = new IPEndPoint(ip, port); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), _socket); } private void ConnectCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; socket.EndConnect(ar); } public void Send(string data) { byte[] byteData = Encoding.ASCII.GetBytes(data); _socket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), _socket); } private void SendCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; int bytesSent = socket.EndSend(ar); Console.WriteLine("Sent {0} bytes to server.", bytesSent); } public void Receive() { _socket.BeginReceive(_buffer, 0, _buffer.Length, 0, new AsyncCallback(ReceiveCallback), _socket); } private void ReceiveCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; int bytesRead = socket.EndReceive(ar); if (bytesRead > 0) { string data = Encoding.ASCII.GetString(_buffer, 0, bytesRead); Console.WriteLine("Received: {0}", data); } } public void Close() { _socket.Shutdown(SocketShutdown.Both); _socket.Close(); } } ``` 这个示例中,我们创建了一个名为 `SocketClient` 的类,该类实现了一个基本的 TCP 客户端。在构造函数中,我们使用指定的 IP 地址和端口号初始化了一个 `IPEndPoint` 对象,并创建了一个 `Socket` 对象。在连接服务器时,我们使用 `BeginConnect` 方法异步地连接服务器,并在连接成功后调用 `ConnectCallback` 方法。在发送数据时,我们使用 `BeginSend` 方法异步地发送数据,并在发送完成后调用 `SendCallback` 方法。在接收数据时,我们使用 `BeginReceive` 方法异步地接收数据,并在接收完成后调用 `ReceiveCallback` 方法。在关闭客户端时,我们使用 `Shutdown` 方法关闭连接并调用 `Close` 方法释放资源。 以上是一个简单的 C# Socket 封装示例,实际应用中,可能需要根据具体需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值