隐藏

.NET平台下C#的Socket通信

发布:2022/1/21 13:34:02作者:管理员 来源:本站 浏览次数:931

一、什么是Socket?(what?)

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

Socket是面向客户/服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用。

简单也可以理解客户端和服务端之间的通信。

二、socket连接原理?(how?)

服务器监听:服务器端socket并不定位具体的客户端socket,而是处于等待监听状态,实时监控网络状态。

客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。为此,clientSocket必须知道serverSocket的地址和端口号,进行扫描发出连接请求。

连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

异步通信,简单来说就是服务器端和客户端可以进行多次互发信息的通信而不用担心通道会关闭。

连接过程图示:

三、C#代码实现(很简单的demo,没有考虑其他可能出现的通信问题,比如连接超时等)

客户端代码:

    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;

    private string getServerMessage(string customerId)
            {
                //设定服务器IP地址
                var serverIP = "127.0.0.1";
                var serverPort ="8888";
                IPAddress ip = IPAddress.Parse(serverIP);
                Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    //服务器连接成功
                    clientSocket.Connect(new IPEndPoint(ip, serverPort)); //配置服务器IP与端口
                }
                catch
                {
                    return "连接服务器失败!";
                }
     
                var recStr = "";
                try
                {
                    //发送数据
                    var sendCustomerId = customerId;
                    byte[] sendBytes = Encoding.UTF8.GetBytes(sendCustomerId);
                    clientSocket.Send(sendBytes);
     
                    //接收数据, 注意编码格式
                    byte[] resBytes = new byte[1024];
                    int bytes = clientSocket.Receive(resBytes, resBytes.Length, 0);
                    recStr += Encoding.UTF8.GetString(resBytes, 0, bytes);
                }
                catch
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                    recStr = "接收消息失败";
                }
                //返回数据
                return recStr;
            }

服务端代码:

    class Program
        {
     
            private static byte[] result = new byte[1024];
            private static int myProt = 8888; //端口
            static Socket serverSocket;
            static void Main(string[] args)
            {
                //服务器IP地址
                IPAddress ip = IPAddress.Parse("127.0.0.1");
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.Bind(new IPEndPoint(ip, myProt));//绑定IP地址:端口
                serverSocket.Listen(10); //设定最多10个排队连接请求
                Console.WriteLine("启动监听{0}成功", serverSocket.LocalEndPoint.ToString());
                //通过Clientsoket发送数据
                Thread myThread = new Thread(ListenClientConnect);
                myThread.Start();
                Console.ReadLine();
            }
     
            /// <summary>
            /// 监听客户端连接
            /// </summary>
            private static void ListenClientConnect()
            {
                while (true)
                {
                    Socket clientSocket = serverSocket.Accept();
                    Thread receiveThread = new Thread(ReceiveMessage);
                    clientSocket.Send(Encoding.GetEncoding("GBK").GetBytes("00000124SX27|1529"));
                    receiveThread.Start(clientSocket);
                }
            }
     
            /// <summary>
            /// 接收消息
            /// </summary>
            /// <param name="clientSocket"></param>
            private static void ReceiveMessage(object clientSocket)
            {
                Socket myClientSocket = (Socket)clientSocket;
                while (true)
                {
                    try
                    {
                        //通过clientSocket接收数据
                        int receiveNumber = myClientSocket.Receive(result);
                        Console.WriteLine("接收客户端{0}消息{1}", myClientSocket.RemoteEndPoint.ToString(), Encoding.GetEncoding("GBK").GetString(result, 0, receiveNumber));
                        Console.WriteLine("返回数据");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        myClientSocket.Shutdown(SocketShutdown.Both);
                        myClientSocket.Close();
                        break;
                    }
                }
            }
        }

 

四、遇到的问题

中文乱码::一般UTF-8,客户端和服务端的编码格式要一致,否则就会乱码

                     这样可以自定义编码格式:recStr += Encoding.GetEncoding("gbk").GetString(resBytes, 0, bytes);

 

参考链接:

https://baike.baidu.com/item/socket/281150?fr=aladdin

https://www.cnblogs.com/ysyn/p/3399351.html