C# 的TCP Socket (同步方式)带来的问题及异步方式来处理

 如下代码是同步方式创建Server

        static void Main(string[] args)
        {
            /*
            Thread th = new Thread(new ThreadStart(SocketInit));
            th.IsBackground = true;
            th.Start();*/
            SocketInit();
            Console.ReadKey();
        }

        static void SocketInit()
        {
            //负责监听的SocketWatch,基于TCP的Stream Socket(流式套接字)
            Socket SocketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse("169.254.156.13");
            IPEndPoint point = new IPEndPoint(ipAddress, 20002);
            SocketWatch.Bind(point);//将SocketWatch绑定到主机上面的某个端口
            SocketWatch.Listen(10); //启动监听,并且设置一个最大的队列长度
            Console.WriteLine("Server is ready!");

            //循环等待客户端连接
            while (true)
            {
                //负责监听的socket调用其Accept()来创建一个负责通信的SocketSend
                Socket SocketSend = SocketWatch.Accept();


                byte[] buffer = new byte[2048 * 2048];//字节数组:接收Client发送的消息
                int r= SocketSend.Receive(buffer);
                
                string MsgReceive = Encoding.UTF8.GetString(buffer, 0, r);
                Console.WriteLine($"server 收到Client的消息:{MsgReceive}");
                
                Thread.Sleep(100);//接收大量数据的时候,特别是超过1k时,一定要使用Thread.Sleep(10)函数,以便cpu有时间来处理数据到缓冲区
                string strReceive = buffer[2].ToString();
                if (strReceive=="6")
                {
                    byte[] byteSend = new byte[10] { 0xEA, 0xEB, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFB };
                    SocketSend.Send(byteSend);

                    string MsgSend = Encoding.UTF8.GetString(byteSend, 0, 10);
                    Console.WriteLine($"Server给Client发的消息{MsgSend}");
                }

            }
        }

 Client第一次给Server发送消息,Server能收到,但是第二次之后,Server就收不到消息了!

这时候把Client先断开,在重连 上Server,再发送消息,这样可以进行发送

但是这时候你是创建了一个新的Client实例,端口和你上一次创建的不一样。

原因出自于,Server中

SocketWatch.Accept();

SocketSend.Receive(buffer);

这两句改成异步执行即可,如下代码是用开启相应线程封装这两句方法:

        static void Main(string[] args)
        {
            /*
            Thread th = new Thread(new ThreadStart(SocketInit));
            th.IsBackground = true;
            th.Start();*/
            SocketInit();
            Console.ReadKey();
        }

        static void SocketInit()
        {
            //负责监听的SocketWatch,基于TCP的Stream Socket(流式套接字)
            Socket SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse("169.254.156.13");
            IPEndPoint point = new IPEndPoint(ipAddress, 20002);
            SocketWatch.Bind(point);//将SocketWatch绑定到主机上面的某个端口
            SocketWatch.Listen(10); //启动监听,并且设置一个最大的队列长度
            Console.WriteLine("Server is ready!");

            Thread threadWatch = new Thread(()=> {
                //循环等待客户端连接
                while (true)
                {
                    //负责监听的socket调用其Accept()来创建一个负责通信的SocketSend
                    Socket SocketSend = SocketWatch.Accept();

                    Thread threadSend=new Thread(() => {
                        while (true)
                        {
                            byte[] buffer = new byte[2048 * 2048];//字节数组:接收Client发送的消息
                            int r = SocketSend.Receive(buffer);

                            string MsgReceive = Encoding.UTF8.GetString(buffer, 0, r);
                            Console.WriteLine($"server 收到Client的消息:{MsgReceive}");

                            //Thread.Sleep(100);//接收大量数据的时候,特别是超过1k时,一定要使用Thread.Sleep(10)函数,以便cpu有时间来处理数据到缓冲区
                            string strReceive = buffer[2].ToString();
                            if (strReceive == "6")
                            {
                                byte[] byteSend = new byte[10] { 0xEA, 0xEB, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFB };
                                SocketSend.Send(byteSend);
                                string MsgSend = Encoding.UTF8.GetString(byteSend, 0, 10);
                                Console.WriteLine($"Server给Client发的消息{MsgSend}");
                            }
                        }
                    });
                    threadSend.IsBackground = true;
                    threadSend.Start();
                }
            });
            threadWatch.IsBackground = true;
            threadWatch.Start();
            Console.WriteLine("开启监听。。。");



        }

异步方式源码如下:

Server端:

using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace AsyncSocketTest
{
    public static class Server
    {
        //此代码在同个时间点发送多个包时。接受包就会出现问题,涉及TCP粘包处理。在服务端,需要为每个客户端连接提供一个 byte[]缓冲区,不要做成共用一个缓冲区

        static byte[] buffer = new byte[2048];//每个客户端连接都共用了一个缓冲区,
        static void Main(string[] args)
        {
            var socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse("169.254.156.13");
            IPEndPoint point = new IPEndPoint(ipAddress, 20002);
            socketListener.Bind(point);
            socketListener.Listen(4);

            //Accept Cilent Request
            socketListener.BeginAccept(AcceptReceiveDataCallback, socketListener);

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

        static void AcceptReceiveDataCallback(IAsyncResult ar)
        {
            // Get the socket that handles the client request.
            Socket SocketListener = ar.AsyncState as Socket;
            Socket SocketHandler = SocketListener.EndAccept(ar);
            if (SocketHandler.Connected)
            {
                //Sending Message to Client
                byte[] WelcomeMsg = Encoding.UTF8.GetBytes("Hi there! I accept you request at " + DateTime.Now.ToString());
                SocketHandler.Send(WelcomeMsg);

                //Sending Message to Client By Timer 实现每隔两秒钟给服务器发一个消息
                var timer = new System.Timers.Timer();
                timer.Interval = 2000;
                timer.Enabled = true;
                timer.Elapsed += (sender, args) =>
                {
                    //检测客户端Socket的状态
                    if (SocketHandler.Connected)
                    {
                        byte[] Msg = Encoding.Unicode.GetBytes("Message from server at " + DateTime.Now.ToString());
                        SocketHandler.Send(Msg);
                    }
                    else
                    {
                        timer.Enabled = false;
                        timer.Stop();
                        Console.WriteLine("Client is disconnected, the timer is stop.!");
                    }
                };
                timer.Start();
            }
            //接收客户端的消息(这个和在客户端实现的方式是一样的)
            SocketHandler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, SocketHandler);

            //准备接受下一个客户端请求
            SocketHandler.BeginAccept(AcceptReceiveDataCallback, SocketHandler);
        }

        static void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                Socket SocketHandler = ar.AsyncState as Socket;
                int Length = SocketHandler.EndReceive(ar);
                
                //读取出来消息内容
                var Msg = Encoding.Unicode.GetString(buffer, 0, Length);
                Console.WriteLine(Msg);

                //接收客户端的消息(这个和在客户端实现的方式是一样的)
                SocketHandler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, SocketHandler);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Client端:

using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace AsyncSocketClient
{
    class Client
    {
        static byte[] buffer = new byte[1024];//设置一个缓冲区,用来保存数据
        static void Main(string[] args)
        {
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse("169.254.156.13");
            socket.Connect(ip, 20002);
            Console.WriteLine("Connect to the server!");

            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, socket);

            //接受用户输入,将消息发送给服务器端
            while (true)
            {
                var message = "Message from client : " + Console.ReadLine();
                var outputBuffer = Encoding.Unicode.GetBytes(message);
                socket.BeginSend(outputBuffer, 0, outputBuffer.Length, SocketFlags.None, null, null);
            }
        }

        static void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                Socket socket = ar.AsyncState as Socket;
                int Length = socket.EndReceive(ar);
                var Msg = Encoding.UTF8.GetString(buffer, 0, Length);
                Console.WriteLine(Msg);

                //Receive Next Message
                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, socket);
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }

    }
}

异步写法参考:https://www.cnblogs.com/chenxizhang/archive/2011/09/10/2172994.html#!comments

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值