基于Socket通信的小实例

作者: 牛水聿 | 来源:发表于2017-08-24 09:01 被阅读98次

    距离上次更博已经好长的时间了,上班了工作了,确实空闲下来的时间少了,然而我更多的在思考在于,写些啥,有啥东西是可以放进博客里的,千篇一律的教程亦或是自己研究出来的东西,我想更应该是后者吧,不然我这博客也是搭得没意思。

    话不多说,今天我们来了解下Socket相关的知识,可以说的上是基础,做了点小通信(其实也简单啦)~

    实现效果

    先说整个实例在实现效果上,由于本实例只是对Socket相关的使用做了个基本的测试,所以在效果上确实是差强人意,也就不上图了,大体的效果描述就是:在Unity搭建的客户端,创建的UI按钮上进行点击,给服务端进行消息的发送,而后服务端返回相应的消息,不同的消息发送有不同的回应而已。

    效果不重要,毕竟才基础,里面的原理才是我们需要了解的~

    服务端搭建

    这里的服务端,博主采取的是通过VS创建控制台程序,在电脑上开启服务端代码,主程序入口如下

    Program.cs

     using System;
        class Program
            {
                static void Main(string[] args)
                {
                    Server server = new Server("127.0.0.1",8899);
                    server.Start();
        
                    Console.ReadKey();
                }
            }
    
    

    其实主程序无非就是创建了服务类,开启服务而已,而这里的服务类就是Socket相关使用的主体了

    Server.cs

     using System;
        using System.Collections.Generic;
        using System.Net;
        using System.Net.Sockets;
        class Server
            {
                private Socket serverSocket;
                private Socket clientSocket;
                private IPAddress ipAddress;
                private IPEndPoint ipEndPoint;
                private List<Client> clientList = new List<Client>();
        
                public Server(string ip,int port)
                {
                    //创建Socket
                    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    //声明ip地址和端口号
                    this.ipAddress = IPAddress.Parse(ip);
                    this.ipEndPoint = new IPEndPoint(ipAddress, port);
                }
        
                public void Start()
                {
                    //Socket绑定IP和端口号
                    serverSocket.Bind(ipEndPoint);
                    //Socket开始监听
                    serverSocket.Listen(0);
        
                    Console.WriteLine("服务器已经启动");
        
        
                    //客户端接入
                    serverSocket.BeginAccept(AcceptCallback,null);
                }
        
                private  void AcceptCallback(IAsyncResult ar)
                {
                    clientSocket = serverSocket.EndAccept(ar);
                    //获取客户端名称
                    string clientName = clientSocket.RemoteEndPoint.ToString();
                    Client client = new Client(clientSocket, clientName);
                    client.Start();
                    Console.WriteLine(clientName + "已经登录。。。");
        
                    clientList.Add(client);
        
                    //继续循环监听客户端的连接
                    serverSocket.BeginAccept(AcceptCallback, null);
                }
            }
    
    

    Server类的主要功能无非就是开启个Socket绑定确定的IP和端口,时刻监听客户端的连接。程序在这里采取的是异步方式,之所以代码上没有明显的线程调用,是因为在采用了封装好的API,像 BeginXXX 这样的函数,为了能够循环监听客户端的连接也是在AcceptCallback里面继续开启客户端的监听,大体的逻辑是这样。

    而这里的Client类可不是代表实际意义上的客户端,这里只是对客户端进行的相关管理,主要是对客户端的消息发送和接收进行着处理,之所以采取两个类的方式,也是受到面向对象思想的影响,同样便于代码的管理。

    Client.cs

     using System;
        using System.Text;
        using System.Net.Sockets;
        class Client
            {
                private Socket clientSocket;
                private string clientName;
                private byte[] recieveData;
        
                public Client(Socket client,string clientName)
                {
                    this.clientSocket = client;
                    this.clientName = clientName;
                    recieveData = new byte[clientSocket.ReceiveBufferSize];
                }
        
                public void Start()
                {
                    clientSocket.BeginReceive(recieveData,0, clientSocket.ReceiveBufferSize,SocketFlags.None, RecieveCallback, null);
                }
        
                //接收客户端的消息
                private void RecieveCallback(IAsyncResult ar)
                {
                    try
                    {
                        //接收到的数据长度
                        int count = clientSocket.EndReceive(ar);
        
                        //防止客户端异常退出
                        if (count == 0)
                        {
                            clientSocket.Close();
                            return;
                        }
        
                        //对接收到的数据进行处理
                        string msgRec = Encoding.UTF8.GetString(recieveData, 0, count);
                        HandleResponse(msgRec);
        
                        //输出到控制台
                        Console.WriteLine(msgRec);
        
                        //循环接收客户端发送过来的数据
                        clientSocket.BeginReceive(recieveData, 0, clientSocket.ReceiveBufferSize, SocketFlags.None, RecieveCallback, null);
                    }
                    catch (Exception)
                    {
                        if (clientSocket != null)
                        {
                            clientSocket.Close();
                            return;
                        }
                    }
                    
                }
        
                //对客户端返回过来的数据进行处理
                private void HandleResponse(string data)
                {
                    if (data.Equals("hello"))
                    {
                        SendMessage("hello too");
                    }else if (data.Equals("haha"))
                    {
                        SendMessage("heihei");
                    }
                }
        
                //发送消息给客户端
                private void SendMessage(string data)
                {
                    byte[] msgData = Encoding.UTF8.GetBytes(data);
                    clientSocket.Send(msgData);
                }
            }
    
    

    服务器端对客户端发出的请求是在对消息解析后才处理的,也就是我们的HandleResponse函数里面,这里只是简单的对客户端发送过来的字符串进行简单的if else判断而已~

    客户端创建

    相对服务器端的构建,客户端算是简单了许多,这里也就只有一个类来测试的。

    Client.cs

     using UnityEngine;
        using System.Text;
        using System.Net.Sockets;
        using System.Net;
        using System;
        using UnityEngine.UI;
        public class Client : MonoBehaviour {
        
            private Socket clientSocket;
            private byte[] recieveData;
            private Button btn1;
            private Button btn2;
            // Use this for initialization
            void Start () {
        
                InitNet();
        
                btn1 = transform.Find("Btn1").GetComponent<Button>();
                btn2 = transform.Find("Btn2").GetComponent<Button>();
        
                btn1.onClick.AddListener(() => {
                    SendMsg("hello");
                });
        
                btn2.onClick.AddListener(() => {
                    SendMsg("haha");
                });
            }
        
            private void InitNet()
            {
                // 首先声明一个Socket
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //申明IP和端口号
                IPAddress iPAddress = IPAddress.Parse("127.0.0.1");
                IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 8899);
                //连接服务器端
                clientSocket.Connect(iPEndPoint);
        
                //接收服务端发送过来的消息
                recieveData = new byte[clientSocket.ReceiveBufferSize];
                clientSocket.BeginReceive(recieveData, 0, clientSocket.ReceiveBufferSize, SocketFlags.None, RevieveCallback, null);
            }
        
            private void RevieveCallback(IAsyncResult ar)
            {
                int count = clientSocket.EndReceive(ar);
                string msgRec = Encoding.UTF8.GetString(recieveData, 0, clientSocket.ReceiveBufferSize);
                //输出信息
                Debug.Log(msgRec);
                recieveData = new byte[clientSocket.ReceiveBufferSize];
                clientSocket.BeginReceive(recieveData, 0, clientSocket.ReceiveBufferSize, SocketFlags.None, RevieveCallback, null);
            }
        
            private void SendMsg(string data)
            {
                byte[] sendMsg = Encoding.UTF8.GetBytes(data);
                clientSocket.Send(sendMsg);
            }
        }
    
    
    

    在客户端初始Socket,确认IP和端口号就能连上服务器了,然后通过Unity的组件进行消息的发送,然后接收相关消息,流程一步了然,简直不要太简单~

    源码地址

    源码工程已上传Github了,在这里

    总结

    通过这个小的实例可以了解到Socket的基本编程,以及简单的网络通信,当然这只是在局域网下能够通信哈,而后博主也是会加大难度,基于此开发一个网络游戏,在广域网下也能完美运行(当然现在服务器都没有233333)

    就这么多,白了个白~

    相关文章

      网友评论

        本文标题:基于Socket通信的小实例

        本文链接:https://www.haomeiwen.com/subject/ioesdxtx.html