TCP服务器编程CPU占有率过高问题

米兰张 2013-09-22 12:25:44
有几个问题需要咨询下各位大侠,采用的是tcplistener和tcpclient类客户端和服务端都在自己电脑上,客户端为网上下载测试工具。
1:当服务器端和客户端在通信的时候,CPU占用基本为0,但是当客户端断开连接的时候,CPU占用率一下达到25%,如果再断开,再连接CPU占用率还会上升。
2:当同一Ip第一次连接的时候,异步接收BeginAcceptTcpClient能执行,断开第二次再连接就不能执行,此时其它IP连接能执行。
MyTcpListenerInfo.MyTcpListener[Index].BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClient), MyTcpListenerInfo.MyTcpListener[Index]);
对这个问题我是采用在DoAcceptTcpClient函数及其调用函数中使用了循环
for (int i = 0; i < MyTcpListenerInfo.MyTcpListener.Count; i++)
{
if (MyTcpListenerInfo.MyTcpListener[i].Pending())
{


MyTcpListenerInfo.MyTcpListener[i].BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClient), MyTcpListenerInfo.MyTcpListener[i]);


}

}
来判断是否有新的连接接入,如果有则开始异步接收。这样做是否合理,还有这个异步模式是否包含IOCP。

3:对于高性能的TCP服务器,是否最好使用SocketAsyncEventArgs?

请各位大侠指点下,非常感谢!
...全文
674 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
米兰张 2013-09-23
  • 打赏
  • 举报
回复
问题自己解决了,没有使用SocketAsyncEventArgs,如果发现客户端失去连接就break出while(true)循环,并释放tcpclient及其它资源,然后再启动一个异步接收动作 MyTcpListener[0].BeginAcceptTcpClient (new AsyncCallback (AcceptClient), MyTcpListener[0]);
米兰张 2013-09-22
  • 打赏
  • 举报
回复
嗯!之前也看见了你在其它一个帖子的回复,那么请问下,你是怎么处理的。同一个IP多次接入,按照我的方法,客户端每次都能连接到服务端,但是如果不使用pengding监测,那么第二次连接就不能被处理,也就是异步的BeginAcceptTcpClient不能被处理。 是否最好使用SocketAsyncEventArgs,谢谢!
  • 打赏
  • 举报
回复
我在通讯层的程序中从没有使用过循环语句,也从没有阻塞(WaitOne之类的)语句。
米兰张 2013-09-22
  • 打赏
  • 举报
回复
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using System.Net; using System.IO; using System.Net.Sockets; namespace SocketTest { public partial class Server : Form { public Server() { InitializeComponent(); } TcpListenerInfo MyTcpListenerInfo = new TcpListenerInfo(); private void StartTcpServer() { SetTcpListener(); } private void SetTcpListener() //设置TCP监听 { for (int i = 0; i < MyTcpListenerInfo.MyIpPort.Count; i++) { MyTcpListenerInfo.MyIPEndPoint.Add(new IPEndPoint(IPAddress.Any, MyTcpListenerInfo.MyIpPort[i]));//创建并加入到实际的IPEndPoint实例 MyTcpListenerInfo.MyTcpListener.Add(new TcpListener(MyTcpListenerInfo.MyIPEndPoint[i]));//加入到实际的监听列表 MyTcpListenerInfo.IsKeepAlive.Add(true); MyTcpListenerInfo.Index.Add(i); MyTcpListenerInfo.MyTcpListener[i].Start();//开始监听 MonitorTcpListener(i); } } private void MonitorTcpListener(int Index) { MyTcpListenerInfo.MyTcpListener[Index].BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClient), MyTcpListenerInfo.MyTcpListener[Index]); } private void DoReceiveData(TcpListener MyTcpListener,TcpClientInfo MyTcpClientInfo) { for (int i = 0; i < MyTcpListenerInfo.MyTcpListener.Count; i++) { if (MyTcpListener.Equals(MyTcpListenerInfo.MyTcpListener[i]) == true) { MyTcpClientInfo.Index = i; ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), MyTcpClientInfo); break; } } } private void DoAcceptTcpClient(IAsyncResult ar)//发生Tcp连接时执行 { TcpClientInfo MyTcpClientInfo = new TcpClientInfo(); TcpListener MyTcpListener = (TcpListener)ar.AsyncState; MyTcpClientInfo.MyTcpClient = MyTcpListener.EndAcceptTcpClient(ar); //ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), MyTcpClientInfo.MyTcpClient); DoReceiveData(MyTcpListener,MyTcpClientInfo); } private void ReceiveBuffer(ref string BufferString,TcpClient MyTcpClient,NetworkStream MyNetworkStream) { Byte[] Buffer = new Byte[256]; int Bufferlen = 0; try { if (MyTcpClient.Available>0) { BufferString=""; Bufferlen=MyNetworkStream.Read(Buffer, 0, Buffer.Length); BufferString = System.Text.Encoding.ASCII.GetString(Buffer, 0, Bufferlen); } } catch { } } private void SendData(string SendString, StreamWriter MyStreamWriter) { MyStreamWriter.WriteLine("Recvice String Is=" + SendString); MyStreamWriter.Flush(); } private void ReceiveData(object Obj)//Index为端口的序列号 { int BeginTime = System.Environment.TickCount; NetworkStream MyNetworkStream = (Obj as TcpClientInfo).MyTcpClient.GetStream(); StreamReader MyStreamReader = (new StreamReader(MyNetworkStream)); StreamWriter MyStreamWriter = (new StreamWriter(MyNetworkStream)); string data = ""; Byte[] bytes = new Byte[256]; while (true) { /* for (int i = 0; i < MyTcpListenerInfo.MyTcpListener.Count; i++) { if (MyTcpListenerInfo.MyTcpListener[i].Pending()) { MyTcpListenerInfo.MyTcpListener[i].BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClient), MyTcpListenerInfo.MyTcpListener[i]); } } */ try { int i; if ((i = MyNetworkStream.Read(bytes, 0, bytes.Length)) != 0) { BeginTime = System.Environment.TickCount;//重新获取时间搓 if (true) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); if (data != "") { MyStreamWriter.WriteLine("Recvice String Is=" + data); MyStreamWriter.Flush(); } if (data == "") { //MyNetworkStream.Dispose(); // MyStreamReader.Dispose(); // MyStreamWriter.Dispose(); // break; } } } if (System.Environment.TickCount - BeginTime >= 5000) { // (Obj as TcpClientInfo).MyTcpClient.Close(); // MyNetworkStream.Dispose(); // MyStreamReader.Dispose(); // MyStreamWriter.Dispose(); // break; } } catch { } finally { // MyNetworkStream // MyStreamReader // MyStreamWriter } } } private void btnOpen_Click(object sender, EventArgs e) { for (int i = 16001; i <= 16001;i++ ) { MyTcpListenerInfo.MyIpPort.Add(i); } Thread T = new Thread(StartTcpServer); T.Start(); } private void Server_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { } private void timer1_Tick(object sender, EventArgs e) { // RollLisListen(); } } class TcpListenerInfo { public List<TcpListener> MyTcpListener = new List<TcpListener>();//TCP通信监听 public List<IPEndPoint> MyIPEndPoint = new List<IPEndPoint>();//IPEndPoint实例 public List<int> MyIpPort = new List<int>();//需要监听的端口 public List<bool> IsKeepAlive = new List<bool>();//是否接收数据的标识 public List<int> Index = new List<int>(); } class TcpClientInfo { public TcpClient MyTcpClient = new TcpClient(); public int Index = 0; } } 这个是全部源码!
ycg_893 2013-09-22
  • 打赏
  • 举报
回复
我看网上有很多SocketAsyncEventArgs实例,我个人认为很多不成熟,不可照般的应用于实际项目中,像MSDN的例子就是一个不成熟的代码。而有一些虽然解决状态的问题,但没有处理粘包等问题。所以如果没有充分解决这些问题又不需要跨平台和跨客户端的话,建议使用一些成熟框架如WCF等。这些就不需要处理这些麻烦的问题,当然学习还是可以的。
ycg_893 2013-09-22
  • 打赏
  • 举报
回复
使用SocketAsyncEventArgs是可以的,但在服务器只能用于接受与接收,不可用于发送,因为SocketAsyncEventArgs的状态只能是接受、接收、发送的状态之一,如果正在接收,你这时发送的话就会导致状态无效的异常,而接收总是在接受之前不存在这个问题,不过也有一个例外,那就是客户端连接已建立,但未发送数据到服务器端,这时服务器断开客户端连接也会发生状态无效的异常,所以需要处理好这个异常。 通常一个SocketAsyncEventArgs实例是可以重复使用,以提高服务器性能,若没有处理好这个异常则会导致这个实例再也无法使用。

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧