*****求助 c# Socket服务器 大概200台设备(客户端只发数据)****

SomethingJack 2015-11-14 01:07:08
需求是这样的,我负责编写一个c# socket服务端,接收200台(以后会更多)设备每50MS的数据 合包处理 然后解析数据存放入数据库,注意带winform界面,显示每一台设备的连接状态。目前的问题是。由于数据量快而且大,每次程序会崩溃,所以我来请教一下,一般这种类似的情况 你们是如何处理的 或者给我一些好的资源 ,谢谢!以下是我实现的部分通讯代码过程,希望指教

/// 建立连接zuo
/// </summary>
private void ServerStar()
{
this.SocketServer("192.168.235.170", 4005);
}

/// <summary>
/// 服务端
/// </summary>
private void SocketServer(string host, int port)
{
try
{
//服务器IP地址
IPAddress ip = IPAddress.Parse(host);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ip, port)); //绑定IP地址:端口
serverSocket.Listen(500);

this.label1.Text = string.Format("启动监听{0}", serverSocket.LocalEndPoint.ToString());

//通过Clientsoket发送数据
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
}

catch (ArgumentNullException ex)
{
LogHelper.CreateLogTxt("ArgumentNullException" + ex.Message);
}
catch (SocketException ex)
{
LogHelper.CreateLogTxt("SocketException" + ex.Message);
}
}

/// <summary>
/// 监听客户端连接
/// </summary>
private void ListenClientConnect()
{
try
{
Socket clientSocket = serverSocket.Accept();
if (clientSocket.Connected == true)
{
//获取请求连接的IP
IPAddress clientIP = ((IPEndPoint)clientSocket.RemoteEndPoint).Address;
ipaddrssList.Add(clientIP);

Thread thread = new Thread(new ParameterizedThreadStart(ReceiveMessage));
thread.Start(clientSocket);
}
}
catch (Exception ex)
{
LogHelper.CreateLogTxt(ex.Message);
}
}
...全文
458 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
wizzly 2016-02-15
  • 打赏
  • 举报
回复
地址早忘记了,发一个关键词,你按照这个去搜索,是可以找到的。 SocketAsyncEventArgsPool 应用线程池技术。
LinuxCard 2015-11-17
  • 打赏
  • 举报
回复
50ms一个数据,这个频率挺高的,应该是长连接吧,iocp干这种事情最合适了,所有信息post到界面显示,反正c++是这么玩的,c#应该也茶不错,原理应该差不多
SomethingJack 2015-11-17
  • 打赏
  • 举报
回复
引用 28 楼 wyd1520 的回复:
public static void ReceiveMessage(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); byte[] curBuffer=new byte[length]; System.Buffer.BlockCopy(buffer,0,curBuffer,length); ByteQueue byteQueue = new ByteQueue(); <--这个有问题你要建一个类来存这个对像上上面的那个Session 要不然服务端不知是哪个SOcket过来的。 byteQueue.Enqueue(curBuffer); while (byteQueue.Find()) { byte[] readBuffer = byteQueue.Dequeue(); string data = BitConverter.ToString(readBuffer); if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED")) { var message = BitConverter.ToString(buffer, 0, length); //显示消息 Console.WriteLine(message); socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } 你要参考我上面写的Session自己定义一个类来进一步处理对应的Socket对象。
我不是太明白你的意思 异步的时候 在下面的函数中应该是已经重新建立了一个客户端吧 那么我在最后的接收函数中不就可以处理数据了 你那个session在这一步不是应该就可以确定了吗??或者你按照我这种代码写清楚一点呢 我有点糊涂了 在之前的帖子里你跟我说的是 直接在接收那个函数中使用缓冲

public static void ClientAccepted(IAsyncResult ar)
        {

            var socket = ar.AsyncState as Socket;

            var client = socket.EndAccept(ar);
            client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client);

            //准备接受下一个客户端请求
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
        }
本拉灯 2015-11-17
  • 打赏
  • 举报
回复
public static void ReceiveMessage(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); byte[] curBuffer=new byte[length]; System.Buffer.BlockCopy(buffer,0,curBuffer,length); ByteQueue byteQueue = new ByteQueue(); <--这个有问题你要建一个类来存这个对像上上面的那个Session 要不然服务端不知是哪个SOcket过来的。 byteQueue.Enqueue(curBuffer); while (byteQueue.Find()) { byte[] readBuffer = byteQueue.Dequeue(); string data = BitConverter.ToString(readBuffer); if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED")) { var message = BitConverter.ToString(buffer, 0, length); //显示消息 Console.WriteLine(message); socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } 你要参考我上面写的Session自己定义一个类来进一步处理对应的Socket对象。
本拉灯 2015-11-17
  • 打赏
  • 举报
回复

 while (byteQueue.Find())
                {
                    byte[] readBuffer = byteQueue.Dequeue();
                    string data = BitConverter.ToString(readBuffer);
                    if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                    {
                        var message = BitConverter.ToString(buffer, 0, length);
                        //显示消息
                        Console.WriteLine(message);
                        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);//这句位置放错了
                    }
                }

要这样放



while (byteQueue.Find())
                {
                    byte[] readBuffer = byteQueue.Dequeue();
                    string data = BitConverter.ToString(readBuffer);
                    if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                    {
                        var message = BitConverter.ToString(buffer, 0, length);
                        //显示消息
                        Console.WriteLine(message);
                        
                    }
                }
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
放到While之外
SomethingJack 2015-11-17
  • 打赏
  • 举报
回复
引用 17 楼 wyd1520 的回复:
下面代码只是给你一个思路。。异步用完成端口实现。不保证你能编译通过, 这是从之前写的服务端截了部份COPY过来的。
我记得之前你给我写过一个合包的缓冲器。 是这样的 我现在按照你之前的方式 使用异步服务器 为什么合包会失败呢?你看一下我的使用方式 是不是正确 我之前是在同步使用的。就是你这个find函数是关键。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ConsoleApplication36
{
    class Program
    {
        static void Main(string[] args)
        {
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.0.103"), 4001));
            socket.Listen(500);
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);


            Console.WriteLine("Server is ready!");
            Console.Read();
        }


        public static void ClientAccepted(IAsyncResult ar)
        {

            var socket = ar.AsyncState as Socket;
            var client = socket.EndAccept(ar);
            client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client);
            //准备接受下一个客户端请求
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
        }

        static byte[] buffer = new byte[1024];

        public static void ReceiveMessage(IAsyncResult ar)
        {

            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                ByteQueue byteQueue = new ByteQueue();
                byteQueue.Enqueue(buffer);
                while (byteQueue.Find())
                {
                    byte[] readBuffer = byteQueue.Dequeue();
                    string data = BitConverter.ToString(readBuffer);
                    if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                    {
                        var message = BitConverter.ToString(buffer, 0, length);
                        //显示消息
                        Console.WriteLine(message);
                        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
SomethingJack 2015-11-17
  • 打赏
  • 举报
回复
引用 33 楼 wyd1520 的回复:
[quote=引用 32 楼 SomethingJack 的回复:] 你写出来 写个伪代码给我看看 我去 单独的意思 是不是在 建立新连接那个地方开始加入你说的session类
17楼就是呀,你还没理解么。。你把Session抽出来就是一个类呀。。[/quote] 我去 你在我那个基础上 给我改一下吧 你那个代码 我测试了一下 得不到想要的数据 你看一下 麻烦了 谢谢

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Collections;
using System.Runtime.InteropServices;

namespace ConsoleApplication38
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().SocketServer("192.168.0.103", 4001);
            Console.ReadLine();
        }
        private AsyncCallback m_OnAccept;
        private static Socket serverSocket;

        /// <summary>
        /// 服务端
        /// </summary>
        private void SocketServer(string host, int port)
        {
            m_OnAccept = new AsyncCallback(OnAccept);

            try
            {
                //服务器IP地址
                IPAddress ip = IPAddress.Parse(host);
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.Bind(new IPEndPoint(ip, port));  //绑定IP地址:端口
                serverSocket.Listen(500);    //设定最多250个排队连接请求

                //this.label1.Text = string.Format("启动监听{0}", serverSocket.LocalEndPoint.ToString());

                //通过Clientsoket发送数据  
                serverSocket.BeginAccept(m_OnAccept, serverSocket);
            }

            catch (ArgumentNullException ex)
            {
                //LogHelper.CreateLogTxt("ArgumentNullException" + ex.Message);
            }
            catch (SocketException ex)
            {
                //LogHelper.CreateLogTxt("SocketException" + ex.Message);
            }
        }



        private void OnAccept(IAsyncResult asyncResult)
        {
            Socket m_ServerSocket = (Socket)asyncResult.AsyncState;
            Socket accepted = null;
            if (m_ServerSocket == null)
                return;
            try
            {

                accepted = m_ServerSocket.EndAccept(asyncResult);
            }
            catch (SocketException ex)
            {

            }
            catch (ObjectDisposedException)
            {
                return;
            }
            catch
            {
                return;
            }

            if (accepted != null)
            {
                AcceptSession(accepted);
            }
            m_ServerSocket.BeginAccept(m_OnAccept, m_ServerSocket);
        }

        List<Session> sessionList = new List<Session>();
        private void AcceptSession(Socket socket)
        {
            Session s = new Session(socket);
            sessionList.Add(s);

        }
        public class Session
        {
            ByteQueue queue = new ByteQueue();
            HistoryByteQueue historyQueue = new HistoryByteQueue();
            private SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
            private int _ConnectionID;

            public int ConnectionID
            {
                get { return _ConnectionID; }
                set { _ConnectionID = value; }
            }
            private IPAddress m_Address;
            private string m_ToString;
            private Socket m_Socket;
            private byte[] m_RecvBuffer = new byte[1024];
            int posid;
            public Session(Socket socket)
            {
                m_Socket = socket;
                this.ConnectionID = Interlocked.Increment(ref _ConnectionID);
                receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
                receiveArgs.SetBuffer(m_RecvBuffer, 0, m_RecvBuffer.Length);
                this.m_Address = ((IPEndPoint)this.m_Socket.RemoteEndPoint).Address;
                this.m_ToString = this.m_Address.ToString();
                m_Socket.ReceiveAsync(receiveArgs);
                //根据IP地址查询断面编号
                //posid = RadarStatisticsService.GetPosID(this.m_Address);
            }


            private void OnReceive(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
                {
                    int byteCount = e.BytesTransferred;
                    byte[] buffer = e.Buffer;
                    byte[] readBuffer = new byte[byteCount];
                    System.Buffer.BlockCopy(buffer, 0, readBuffer, 0, byteCount);
                    queue.Enqueue(readBuffer);
                    while (queue.Find())
                    {
                        byte[] reallData = queue.Dequeue();
                        string data = BitConverter.ToString(reallData);
                        if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED"))
                        {
                            string repStr = data.Replace("-", " ");
                            Regex regex = new Regex("07 81 08.{24}");
                            MatchCollection matches = regex.Matches(repStr, 0);
                            if (matches.Count > 0)
                            {
                                //List<T_RadarStatistics> statisticsList = Common.HandleStatisticsData(repStr, this.m_Address, posid);
                                //Thread threadStatistics = new Thread(new ParameterizedThreadStart(GetStatisticsListByIP));  //这是啥线程没看懂
                                //threadStatistics.Start(statisticsList);
                            }
                        }
                    }
                }

            }
        }
    }
}
本拉灯 2015-11-17
  • 打赏
  • 举报
回复
引用 32 楼 SomethingJack 的回复:
你写出来 写个伪代码给我看看 我去 单独的意思 是不是在 建立新连接那个地方开始加入你说的session类
17楼就是呀,你还没理解么。。你把Session抽出来就是一个类呀。。
SomethingJack 2015-11-17
  • 打赏
  • 举报
回复
你写出来 写个伪代码给我看看 我去 单独的意思 是不是在 建立新连接那个地方开始加入你说的session类
本拉灯 2015-11-17
  • 打赏
  • 举报
回复
引用 29 楼 SomethingJack 的回复:
[quote=引用 28 楼 wyd1520 的回复:] public static void ReceiveMessage(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); byte[] curBuffer=new byte[length]; System.Buffer.BlockCopy(buffer,0,curBuffer,length); ByteQueue byteQueue = new ByteQueue(); <--这个有问题你要建一个类来存这个对像上上面的那个Session 要不然服务端不知是哪个SOcket过来的。 byteQueue.Enqueue(curBuffer); while (byteQueue.Find()) { byte[] readBuffer = byteQueue.Dequeue(); string data = BitConverter.ToString(readBuffer); if (data.StartsWith("FF-FF-FF-FF-CA-CB-CC-CD") && data.EndsWith("EA-EB-EC-ED")) { var message = BitConverter.ToString(buffer, 0, length); //显示消息 Console.WriteLine(message); socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } 你要参考我上面写的Session自己定义一个类来进一步处理对应的Socket对象。
我不是太明白你的意思 异步的时候 在下面的函数中应该是已经重新建立了一个客户端吧 那么我在最后的接收函数中不就可以处理数据了 你那个session在这一步不是应该就可以确定了吗??或者你按照我这种代码写清楚一点呢 我有点糊涂了 在之前的帖子里你跟我说的是 直接在接收那个函数中使用缓冲

public static void ClientAccepted(IAsyncResult ar)
        {

            var socket = ar.AsyncState as Socket;

            var client = socket.EndAccept(ar);
            client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client);

            //准备接受下一个客户端请求
            socket.BeginAccept(new AsyncCallback(ClientAccepted), socket);
        }
[/quote] 缓冲是对的,但你所用的缓冲方式不正确。。因为你没有给每个连接建立单独的缓冲,“单独”明白没,你上面是用同一个缓冲来接收所有的连接过来数据,导至你无法区分数据协议了。。。
u010750886 2015-11-16
  • 打赏
  • 举报
回复
引用 8 楼 SomethingJack 的回复:
[quote=引用 7 楼 wyd1520 的回复:] 看了你的代码也是醉了。。。接收200台。。。你一台开一线程。。。。能不卡么。。。你说一个应用能跑的了200个线程么。。 ListenClientConnect 。。。这个只会执行一次吧。。
- - 这不是来请教你了么 给我提供个思路呗[/quote] 用线程池,或者任务并行库。可以减少线程创建,提高效率
xian_wwq 2015-11-16
  • 打赏
  • 举报
回复
按道理200个用户的并发访问,使用Socket + Threads的方案性能上应该也是可以的 如果要考虑后期的扩展,建议还是换下socket模型 楼主可以参考这个 http://blog.csdn.net/tpriwwq/article/details/38032547
失落的神庙 2015-11-16
  • 打赏
  • 举报
回复
像200台机器可以用线程池去接收处理消息 也可以自己开线程去跑。 不过开200个线程去处理每个客户端不太好。
失落的神庙 2015-11-16
  • 打赏
  • 举报
回复
循环ListenClientConnect()方法 画好缓存区域 50M/S么? 那普通路由器端口是10M/S 得注意下。 一个个加。 别一下开200个客户端。
本拉灯 2015-11-16
  • 打赏
  • 举报
回复
200分我喜欢。。。。来把你的完整的代码发上来。。。给你指点指点。。。
江南小鱼 2015-11-16
  • 打赏
  • 举报
回复
任何一个上位机接收的何止200台终端,整点上传数据,远比50ms密集。 前置机表示木有出现崩溃~ 撸主,先定位出崩溃的原因,找到异常代码出来。
  • 打赏
  • 举报
回复
你还是应该先诊断出在哪一行“崩溃”。不要瞎猜。
chuangand 2015-11-16
  • 打赏
  • 举报
回复
为这200分大家也是蛮拼的,虽然我不会这个
xian_wwq 2015-11-16
  • 打赏
  • 举报
回复
赞成21楼的说法 数据接收和数据解析要分离,否则会导致效率低下, 大致思路是接收数据后直接放入线程安全的队列中,立即返回; 数据解析由另外线程来处理
失落的神庙 2015-11-16
  • 打赏
  • 举报
回复
还有接收消息就只接收消息。处理数据不要放接收消息线程里。 try 只try这句就好了 int bytes = myClientSocket.Receive(recvBytes, recvBytes.Length, 0); 客户端异常关闭 这里就会异常了。 没必要全包住。 个人觉得 你优化好代码 开 200个线程去也肯定没啥问题的。 只是会有点卡而已。
加载更多回复(15)

110,537

社区成员

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

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

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