.NET Socket开发之异步Socket

转载 2007年10月15日 15:24:00
在基于.NET的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步Socket了。异步Socket的性能比同步高出很多,但是编写代码比较复杂。因此异步Socket也是网络上讨论比较多的话题。
今天,我们就来讨论一下如何用异步Socket开发网络应用。在此之前我们先讨论两个问题。
一、异步Socket是如何工作的:
那异步Socket是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。
二、什么情况下我们用异步Socket:
有些人认为,异步Socket的性能比同步Socket的性能高很多,应该在各种环境下都用异步Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这样呢?
1、客户端Socket。
2、服务端连接数比较少。
3、连接数很多,但都是短连接。
在这些环境下,我们用同步Socket不但可以简化代码,而且性能并不会比异步Socket低。但在服务端连接比较多而且是长连接的情况下,我们就要使用异步Socket。
现在我们来看看如何用异步Socket编程。
首先,我们要建立一个Socket用来监听:

            Socket _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint localEP 
= new IPEndPoint(_address, _port);
            _listener.Bind(localEP);
            _listener.Listen(
100);
然后创建一个线程来处理客户端连接请求: 我们再来看看回调函数的定义:

        private void ReceiveCallBack(IAsyncResult ar)
        
{
            UserInfo info 
= (UserInfo)ar.AsyncState;
            Socket handler 
= info.socket;
            
int readCount = 0;
            
try
            
{
                readCount 
= handler.EndReceive(ar);//调用这个函数来结束本次接收并返回接收到的数据长度。
            }

            
catch (SocketException)//出现Socket异常就关闭连接
            {
                CloseSocket(info);
//这个函数用来关闭客户端连接
                return;
            }

            
catch
            
{
            }

            
if (readCount > 0)
            
{
                
byte[] buffer = new byte[readCount];
                Buffer.BlockCopy(info.Buffer, 
0, buffer, 0, readCount);
                Analyzer(info, buffer);
//这个函数用来处理接收到的信息。
                try
                
{
                    handler.BeginReceive(info.Buffer, 
0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);//向系统投递下一个接收请求
                }

                
catch (SocketException) //出现Socket异常就关闭连接
                {
                    CloseSocket(info);
                }

                
catch
                
{
                }

            }

            
else //如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
            {
                CloseSocket(info);
            }

        }
接下来我们看看如何发送数据给客户端:

        public void Send(Socket socket, byte message)
        
{
            
try
            
{
                info.socket.BeginSend(message, 
0, _byte.Length, SocketFlags.None, new AsyncCallback(SendCallBack), info);//这里向系统投递一个发送数据的请求,并指定一个回调函数。
            }

            
catch (SocketException ex)
            
{
                CloseSocket(info);
            }

            
catch
            
{
            }

        }
定义发送回调函数:

        private void SendCallBack(IAsyncResult ar)
        
{
            UserInfo info 
= (UserInfo)ar.AsyncState;
            
try
            
{
                info.socket.EndSend(ar);
//调用这个函数来结束本次发送。
            }

            
catch
            
{
            }

        }

 
好了,整个监听、接收、发送的过程就完成了,很简单吧。现在需要说明的是,我在这里接收客户端连接的Accept是用的同步的,我个人认为在这里用同步的会比用异步好一些。因为这样代码简单而且没有性能上的损失。
今天我就写到这里了!下次我们再继续。
posted on 2007-06-13 23:59 牧 野 阅读(2865) 评论(32)  编辑  收藏 所属分类: C#Socket
楼主对异步的认识大错特错
所谓的SOCKET采用异步会取得高效的性能说的就是Accept。我们应该用BeginAccept,因为如果用Accept的话,同时连接数量多的情况下就不能及时回应,而用BeginAccept就会很好的避免这个问题,所谓的SOCKET应该采用异步来提高性能,其实说的就是我们应该用BeginAccept。对于SEND和RECEIVE,你只要开一个线程在处理一个连接其实就相当于是BEGINSEND和BEGINRECEIVE,就是在异步处理了。有人说一个新连接开一个线程不好,如果有1000连接就要开1000个线程,所以应该采用异步,这简直就是天大的笑话,这些笨蛋们远不知道BEGINSEND等方法就是在线程池开的线程来处理。
BEGINSEND和BEGINRECEIVE在。NET1.1里根本就没有这两个方法,难道。NET1.1的SOCKET就不能异步了????????看了楼主的文章,其实很多东西楼主大大的理解错了。
@biaobiao
那你有没有查看过.NET的类库呢??
呵呵…………
BeginSned和BeginReceive可不是简单的丢在线程池里,他是投递到系统内核里去了。由系统内核来调度发送和接收的操作。
还要告诉你一点,在Socket编程中,线程不是越多越好,你知道性能最高的IOCP模式有多少个线程吗?CPU数量×2+2,就这么多。当一个程序的线程达到50个以上时,如果再增加线程,系统的性能会下降很多!看来你还要多学学!
你使用BeginAccept来接收Socket,而用Receive和Send来收发数据,这才是大错特错。回家好好看完书再来讨论。
还有,不要在我这里骂人,不然我会删除你的回复。那些被你骂成笨蛋的恰恰是比你更了解Windows开发的人。
牧野 的这篇文章没啥错的,我赞同他的观点,尤其是关于异步的好处,它绝非简单的把Socket操作抛到线程池里(我在刚开始用.NET 1.0的时候也有过这种想法),而是传给里系统内核,然后系统内核会把它最终传到硬件层,这时候用到的线程甚至根本不是CPU上的,而是通讯硬件中的,这种手法可以大量节约CPU资源.

还有就是关于线程的使用,应该尽量节约,尤其是在做有大量客户连接的服务器时,最好是一两个线程负责所有的客户请求. 我自己用的方法是把所有客户请求抛到一个队列里,有一个线程负责把请求从队列里取出来处理. 它好处有两个:

1. 节省并发线程
2. 是避免了多线程并发处理请求时的线程同步.

如果对异步Socket有疑惑,可以读下大师Jeffrey Richter的<<CLR via C#, Second Edition>>, 其中有一章讲.NET线程和异步操作,比MSDN讲的透彻.

最后说一下,我做开发的年头和数量不在作者之下,以上所说主要来自具体编程的实践体会.
再问一下..Socket断线后 是否可以自动重连

下面是连接程序
我想在网络断开的时候重新连,怎么改,谢谢
加注释的话异常是在已连接的socket申请连接
public void Connect2Server()
{
IPAddress ipAddress = IPAddress.Parse(szSvrIPAddr);
EndPoint remoteEP = new IPEndPoint(ipAddress, SvrPort);
/*
Socket SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

if (SocketClient.Connected)
{
SocketClient.Shutdown(SocketShutdown.Both);
SocketClient.Close();
Thread.Sleep(100);
}
*/

while(!SocketClient.Connected)
{
try
{
SocketClient.Connect(remoteEP);
}
catch(Exception exc)
{
Log.WriteEntry("Connect to Server Error:" + exc.Message, EventLogEntryType.Error, 2);
}
Thread.Sleep(30 * 1000); //30s
}
}
#1楼    回复  引用  查看    
 

            Thread _acceptWorkThread = new Thread(AcceptWorkThread);
            _acceptWorkThread.Start();

        
private void AcceptWorkThread()
        
{
            
while (_isListener)
            
{
                UserInfo info 
= new UserInfo();//这个UserInfo是用来保存客户信息的。
                info.socket = socket;
                Socket socket 
= _listener.Accept();
                
//这里进行其它处理。
                socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//这里向系统投递一个接收信息的请求,并为其指定ReceiveCallBack做为回调函数
            }

        }

C#中Socket通信编程的异步实现

本文将在C#中Socket同步通信的基础上,分析和研究Socket异步编程的实现方法,目的是深入了解Socket编程的基本原理,增强对网络游戏开发相关内容的认识。 什么是Socket编程的异步是实现 ...
  • mss359681091
  • mss359681091
  • 2016年06月30日 15:49
  • 15770

异步 SOCKET 编程 - 发送和接收数据

我本想把发送和接收分开作为两部分,但是最后我决定只略微解释一下 FD_READ ,留下更多的时间来说明更复杂的 FD_WRITE , FD_READ 事件非常容易掌握. 当有数据发送过来时, WinS...
  • Esonpo
  • Esonpo
  • 2013年07月07日 13:38
  • 2808

Socket 同步和异步模式

学习socket 的一些笔记,希望和大家一起讨论 。 一.什么是socket   所谓socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 以J2SDK-1.3...
  • huijunma2010
  • huijunma2010
  • 2016年04月21日 15:04
  • 255

C#中Socket通信编程的异步实现

本文将在C#中Socket同步通信的基础上,分析和研究Socket异步编程的实现方法,目的是深入了解Socket编程的基本原理,增强对网络游戏开发相关内容的认识。什么是Socket编程的异步是实现所谓...
  • qinyuanpei
  • qinyuanpei
  • 2015年03月23日 21:36
  • 5907

c# Socket 异步客户端服务端

废话不多说  直接上代码 服务端: using System; using System.Collections.Generic; using System.ComponentMode...
  • everlasting51
  • everlasting51
  • 2014年02月20日 18:55
  • 1108

C#网络编程系列文章(五)之Socket实现异步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 在.Net中,Sy...
  • zhujunxxxxx
  • zhujunxxxxx
  • 2015年03月15日 21:20
  • 7757

C#中的socket编程入门实例

Socket主要是通过TCP或者UDP协议进行多台主机之间的通讯。由于项目中用到,所以今天就结合项目需求对socket编程的C#表示进行一步一步详细的介绍。 TCP的详细过程我就不多介绍了,这个是网...
  • mevicky
  • mevicky
  • 2015年10月09日 15:57
  • 13816

VB.Net中Socket异步编程的实例

Imports System Imports System.Net Imports System.Net.Sockets Imports System.Text Imports System.Thre...
  • Seal203
  • Seal203
  • 2015年06月09日 07:07
  • 2839

socket 异步双工

socket 异步双工之前没接触过,最近遇到了,看了别人的代码才明白什么意思:发送一次交易数据完成后不用等待这次的响应的返回,另外起一个异步的接收线程处理对方响应的数据,这就是异步;发送和接受使用同一...
  • birdofsky
  • birdofsky
  • 2016年10月12日 17:08
  • 1097

异步SOCKET与同步SOCKET

Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非阻塞模式下,W...
  • baidu_19340981
  • baidu_19340981
  • 2014年09月16日 14:42
  • 2013
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:.NET Socket开发之异步Socket
举报原因:
原因补充:

(最多只允许输入30个字)