Socket之控制台服务端 普通写法

76 阅读4分钟

一、写法流程

1.创建套接字Socket
2.用Bind方法将套接字与本地地址绑定
3.用Listen方法监听
4.用Accept方法等待客户端连接
5.建立连接,Accept返回新套接字
6.用Send和Receive相关方法收发数据
7.用Shutdown方法释放连接
8.关闭套接字

二、写法思路

1、创建Socket成员变量 作为服务器的Socket。
2、创建一个List列表存储客户端的Socket, 因为可能是多台设备 所以用列表存储
3、在Main函数中 进行实例化Socket  设置Soxket的网络协议、传输模式和通信类型
4、进行绑定IP  使用IPEndPoint ipPoint=new IPEndPoint(IPAdress.Parse(ip),port)); socket.Bind(ipPoint);
5、绑定完之后进行监听  使用socket.Listen(监听设备数);
6、建立连接以及收信息(发消息不需要)需要使用异步的方式 去实现循环监听,如果放在主线程的话会卡死  
7、创建 建立连接 异步线程 Thread acceptThread=New Thread(方法名); acceptThread.Start();
8、建立连接方法 AcceptClientConnect  使用while死循环 去获取接入服务端的客户端Socket, Socket clientSocket = socket.Accept(); 然后存放到list容器中。
9、创建收消息 的 异步线程 Thread receiveThread = new Thread(ReceiveMsg);receiveThread.Start();
10、接收消息的方法 ReceiveMsg();创建一个局部Socket变量,以及创建一个字节数组,接收字节长度receiveNum和变量i,使用while死循环,内部遍历List中的Socket,用clientSocket.Available > 0判断是否发送消息至服务端,如果发送了的话,使用接收字节长度receiveNum获取字节长度receiveNum= clientSocket.Receive(resoult);,最后使用线程池去处理客户端发过来的消息ThreadPool.QueueUserWorkItem(HandleMsg, (clientSocket, Encoding.UTF8.GetString(resoult, 0, receiveNum)));
11、ThreadPool.QueueUserWorkItem(HandleMsg, (clientSocket, Encoding.UTF8.GetString(resoult, 0, receiveNum)));使用的是线程池,其中(clientSocket, Encoding.UTF8.GetString(resoult, 0, receiveNum))是传给HandleMsg的元组参数客户端clientSocket和解析成string的消息。
12HandleMsg(object obj)方法 主要是用来将obj转成11中的元组。
13、发消息通过 拿到列表中的Socket调用Send方法 socket.Send(Encoding.UTF8.GetBytes(info));
14、关闭相关Socket是直接遍历列表中的Socket使用Shutdown(SocketShutdown.Both);方法和Close()方法进行关闭,最后使用Clear()清空列表;
15、广播消息是遍历后进行分发Send
16、不懂看代码示例

代码示例

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

namespace TeachTcpExercise
{
    class Program
    {
        static Socket socket;
        static List<Socket> clientSockets=new List<Socket>();

        //使用开关去进行控制接收连接 收消息的循环
        static bool isClose = false; 
        static void Main(string[] args)
        {
            //1、建立Socket 绑定 监听
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
            socket.Bind(ipPoint);  //绑定
            socket.Listen(1024); //监听

            //2、等待客户端连接  创建一个线程去进行接收客户端连接服务端  不会出现卡死的情况
            Thread acceptThread = new Thread(AcceptClientConnect);
            //开启线程
            acceptThread.Start();

            //3、收发信息
            Thread receiveThread = new Thread(ReceiveMsg);
            receiveThread.Start();
            //4、关闭相关
            while (!isClose) 
            {

                string input = Console.ReadLine();
                if(input == "Quit")
                {
                    //把开关变成true  关闭接收消息和接收记客户端的接入
                    isClose = true;
                    for(int i = 0; i < clientSockets.Count; i++)
                    {
                        clientSockets[i].Shutdown(SocketShutdown.Both);
                        clientSockets[i].Close();
                    }
                    clientSockets.Clear();
                    break;
                }
                //广播消息 用于给所有的客户端发消息
                else if(input.Substring(0,2)=="B:")
                {
                    for(int i= 0; i < clientSockets.Count; i++)
                    {
                        clientSockets[i].Send(Encoding.UTF8.GetBytes(input.Substring(2)));
                    }
                }
            }
        }
        
        
        //这个接收客户端连入的方法中 用循环一直去接收
        static void AcceptClientConnect()
        {
            while (true) 
            {
                //clientSocket 接收连入的客户端
                Socket clientSocket = socket.Accept();
                //后面需要用到的话 可以存起来  放入容器中 在外部创建一个字典容器
                clientSockets.Add(clientSocket);
                //向客户端发送消息
                clientSocket.Send(Encoding.UTF8.GetBytes("欢迎连入服务端"));
            }
        }

        //接收消息
        static void ReceiveMsg()
        {
            Socket clientSocket;
            byte[] resoult=new byte[1024*1024];  //接受容器
            int receiveNum; //接收的字节长度
            int i;
            while (!isClose)
            {
                //先遍历列表中的Socket  然后判断每个是否发送过来
                for (i = 0; i < clientSockets.Count; i++)
                {
                    clientSocket = clientSockets[i];
                    //判断是否有客户端发送消息过来
                    //因为就算不发消息过来 这句也会执行 receiveNum= clientSocket.Receive(resoult);
                    //  所以用clientSocket.Available判断是否字节数大于0
                    if (clientSocket.Available > 0)
                    {
                        receiveNum= clientSocket.Receive(resoult);
                        //处理消息的不能放在这里面 需要异步进行处理 
                        //因为放在这 容易不能及时处理其他Socket的消息
                        ThreadPool.QueueUserWorkItem(HandleMsg, (clientSocket, Encoding.UTF8.GetString(resoult, 0, receiveNum)));
                    }
                }
            }
        }
        static void HandleMsg(object obj)
        {
            (Socket s, string str) info = ((Socket s, string str))obj;
            Console.WriteLine("收到客户端{0}发来的信息:{1}", info.s.RemoteEndPoint, info.str);
        }
    }
}