C# Socket 编程之 TcpListener

 

以下是Server的代码,最近在学习网络编程,一直在思考如何开发出高并发的服务器端。经常听说对服务器描述为同时10000个连接,就在想能否用C#写个这样的服务器出来呢。同步编程模型就不考虑了,来看看TcpListener的异步编程模型能否满足需求。

 

	public partial class COMService {
		private int maxLink = 100000;
		private int currentLinked;
      private ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
		public void Start() {

			Thread thread = new Thread(new ParameterizedThreadStart(ShowStat));
			thread.IsBackground = true;
			thread.Start();
			
			TcpListener server = new TcpListener(new System.Net.IPEndPoint(0, 8090));
			server.Start(100);
			tcpClientConnected.Reset();
			IAsyncResult result = server.BeginAcceptTcpClient(new AsyncCallback(Acceptor), server);
			tcpClientConnected.WaitOne();
		}

		private void ShowStat(object o) {
			while (true) {
				lock (typeof(COMService)) {
					Console.WriteLine("当前连接数:" + currentLinked + "/" + maxLink);
				}
				Thread.Sleep(2000);
			}
		}

		private void Acceptor(IAsyncResult o) {
			TcpListener server = o.AsyncState as TcpListener;
			Debug.Assert(server != null);
			TcpClient client = null;
			try {
				client = server.EndAcceptTcpClient(o);
				System.Threading.Interlocked.Increment(ref currentLinked);
				
			} catch {
				
			}
			IAsyncResult result = server.BeginAcceptTcpClient(new AsyncCallback(Acceptor), server);
			if (client == null) {
				return;
			} else {
				Thread.CurrentThread.Join();
			}
			Close(client);
		}

		private void Close(TcpClient client) {
			if (client.Connected) {
				client.Client.Shutdown(SocketShutdown.Both);
			}
			client.Client.Close();
			client.Close();

			System.Threading.Interlocked.Decrement(ref currentLinked);
		}
	}
}

以下是Client的代码:

	public class ClientPool {
		private static List<TcpWork> clients = new List<TcpWork>();

		private static int freeCount;

		private static int workCount;

		private static int maxAllowed =	2;

		private static int minClients = 2;
		/// <summary>
		/// create new instance
		/// </summary>
		private ClientPool() {
		}

		private static ClientPool instance;
		private static readonly object syncInstanceObj = new object();
		public static ClientPool Singleton {
			get {
				if (instance == null) {
					lock (syncInstanceObj) {
						if (instance == null) {
							instance = new ClientPool();
						}
					}
				}
				return instance;
			}
		}

		private static readonly object syncObj = new object();

		public TcpWork GetClient() {
				try {
				TcpWork work = new TcpWork();
				work.Connect("127.0.0.1", 8090);
				work.LingerState = new LingerOption(false, 3);
				work.IsWork = true;
				work.Expired = false;
				workCount++;
				lock (syncObj) {
					clients.Add(work);
				}
				Console.WriteLine(workCount);
				return work;
			} catch (Exception ex){
				Console.WriteLine(ex.Message);
				return null;
			}
		}
	}
Client模拟多线程并发:

	class Program {
		static void Main(string[] args) {
			for (int i = 0; i < 1000; i++) {
				ThreadPool.QueueUserWorkItem(new WaitCallback(Work), null);
			}
			Console.ReadKey();
		}

		private static void Work(object o) {
			ClientPool.Singleton.GetClient();
		}
	}

 

从这个编程模型可以看出,高并发的服务器不光需要满足有多少个并发连接数,每秒创建多少个连接数也是个重要指标~~

 

实际运行上看看,TcpListener每秒大概能创建两个连接,其他的连接会被拒绝,保持的长连接数1000的样子。很明显,TcpListener要被咔嚓掉了~~

 

注意,以上代码仅仅是用来测·试连接用的,这种写法会导致服务器端的连接无法释放~~~~

 

posted @ 2010-12-17 15:59 Birdshover 阅读(2684) 评论(16) 编辑 收藏

 回复 引用 查看   
#1楼2010-12-17 16:02 | 天天      
我想做一个点对点的类似QQ的聊天,不知道好做吗?
 回复 引用 查看   
#2楼[楼主]2010-12-17 16:12 | Birdshover      
@天天
点对点的需要穿透防火墙技术的

 回复 引用 查看   
#3楼2010-12-17 16:17 | huaxiaoyao      
哎,我一般对我的朋友同学称自己是一个打字员,天天对着电脑打我喜欢的英文字母....
 回复 引用 查看   
#4楼2010-12-17 16:26 | 游吟男孩      
你可以试试SocketAsyncEventArgs,用异步的方式.
 回复 引用 查看   
#5楼2010-12-17 16:51 | Kingthy      
BeginXX与EndXX的异步模型,只要连接数一多,CPU占用基本就90%以上了..

以前尝试写一个HTTP代理工具,用的就是这种异步模型,但测试后CPU占用率太高了,后面只好放弃!!

找资料查原因,可能是此种异步模型,会生成非常多的IAsyncResult实例,所以GC都一直没停过,导致CPU占用过高……

 回复 引用 查看   
#6楼2010-12-17 16:59 | henry      
TcpListener不可以慢到这程度吧...是不是代码使用问题.
我用socket建立tcp临听通过BeginAccept的方式来接收连接,每秒大概能处理100个左右的连接.
其实c#处理1W个连接并不是什么难事,困难的是秒同时发送和接收的数据包的处理量.

 回复 引用 查看   
#7楼2010-12-17 17:07 | henry      
还有适当调整System.Threading.ThreadPool.SetMinThreads(a,b );的b参数可以提高响应速度,不过前提是并发量较高的情况下才适应用.

 回复 引用 查看   
#8楼2010-12-17 23:08 | sky@fly      
楼主,,你好 请问你用什么字体??
 回复 引用 查看   
#9楼2010-12-18 01:11 | 大石头      
实际运行上看看,TcpListener每秒大概能创建两个连接,其他的连接会被拒绝,保持的长连接数1000的样子。很明显,TcpListener要被咔嚓掉了~~

很明显,那不可能,要是每秒只能创建两个连接,的确要来没用了,哈哈!

我做到过五千

 回复 引用 查看   
#10楼2010-12-18 10:49 | pser      
@大石头
1秒接收5000个连接还是,保持5000个?

 回复 引用 查看   
#11楼2010-12-18 14:31 | pythonic      
@sky@fly
这个字体是consolas 11号字体

 回复 引用 查看   
#12楼2010-12-18 17:29 | qiuqingpo      
写的挻简单的.只能做DEMO了.要是再深入一点就好了!
 回复 引用 查看   
#13楼2010-12-19 11:02 | sky@fly      
引用pythonic:
@sky@fly
这个字体是consolas 11号字体

但是该字体在VS2005 中找不到??

 回复 引用 查看   
#14楼2010-12-19 12:56 | indexRoad      
想要瞬间 一次链接1000个很难,但是要保持高链接数则是可以的。请去看看 SocketAsyncEventArgs 它是基于 IOCP 的所以要保持连接数10000 以上是没问题的.
基于TCP 的 Socket AsyncEventArgs的编程模型网上不少了。可以去Codeproject 搜搜看。 基本上是新建好 一个SocketAsyncEventArgs 对像池,同时为 Listen 的Socket 绑定一个 SocketAsyncEventArgs .一旦有连接进来,就为返回的Accpet 从池里取出一个SocketAsyncEventArgs,由他负责通讯。

另外我写了一个 有关UDP的UDP 的SocketAsyncEventArgs客户端模拟了10万个同时进行通信.(为啥我写的就没人看呢?)

 回复 引用 查看   
#15楼2010-12-19 22:00 | pythonic      
 回复 引用 查看   
#16楼2011-07-12 16:27 | celeron729      
TcpWork这个类的定义,能否请lz也贴出?