C# Socket编写局域网聊天室(服务器端)

服务器端

需要的引用包括:
using System.Net;
using System.Net.Sockets;
using System.Threading;

首先要创建Socket,将其绑定到本机的ip地址,给它一个端口号。然后开始监听
什么是ip地址和端口号?
每一个计算机都有一个ip地址。通过ip地址可以在网络中访问到计算机。
注:计算机通过不同的连接方式上网会获得不同的ip,这是因为计算机的每一个网卡都有一个ip,插网线和连接wifi以及蓝牙连接网络都会使用不同的网卡,因此也会有不同的ip。
但是仅仅通过ip找到指定的计算机还不行,还需要和指定的程序进行通信,这是就需要用到端口号。端口号就像是每个程序的门牌号。端口号有65,536个,一般选用一个较大的四位数来避免和其他程序的端口号发生冲突。

			Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			tcpServer.Bind(new IPEndPoint(IPAddress.Parse(GetIP()), 8099));//人为设定一个端口号
			tcpServer.Listen(100);//最大连接数为100
			Console.WriteLine("Waiting for connection...");

其中有一个GetIP()函数,用来获取本机IP

		static public string GetIP()
        {
            try
            {
                string HostName = Dns.GetHostName(); //得到主机名
                IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
                for (int i = 0; i < IpEntry.AddressList.Length; i++)
                {
                    //从IP地址列表中筛选出IPv4类型的IP地址
                    //AddressFamily.InterNetwork表示此IP为IPv4,
                    //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                    if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
                    {
                        return IpEntry.AddressList[i].ToString();
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error getting local IP: " + ex.Message);
                return "";
            }
        }

通过调用Socket.Accept()函数来接收一个来自客户端的连接请求,若没有连接请求,则程序会暂停在这里,直到有客户端连过来。Socket.Accept()函数会返回一个Socket对象,用来表示那个连过来的客户端。我们用一个while死循环来不断处理连接请求。并创建一个类Client来方便处理客户端的一些其他操作。由于会有多个客户端连接过来,创建一个List来管理折现Client对象。

			while(true)
            {
                Socket cs = tcpServer.Accept();
                clientList.Add(new Client(cs));
                Console.WriteLine("Accept a client");
            }

创建客户端对象链表

static private List<Client> clientList = new List<Client>();

客户端类Client

class Client
    {
        private Socket cSocket;
        private Thread cThread;
        private byte[] data = new byte[1024];
        public Client(Socket s)
        {
            cSocket = s;
            cThread = new Thread(ReceiveMsg);
            cThread.Start();
        }
        private void ReceiveMsg()//接收来自客户端的消息
        {
            while(!cSocket.Poll(10, SelectMode.SelectRead))
            {
                try
                {
                    int len = cSocket.Receive(data);
                    //Console.WriteLine("Receive a message:");
                    string Message = Encoding.UTF8.GetString(data, 0, len);
                    //Console.WriteLine(Message);
                    Program.BroadcastMsg(Message);
                }
                catch(Exception e)
                {

                }
            }
            cSocket.Close();
        }
        public void SendMsg(string msg)//向客户端发送消息
        {
            cSocket.Send(Encoding.UTF8.GetBytes(msg));
        }
        public bool isConnected
        {
            get { return cSocket.Connected;}
        }
    }

在Client的构造函数里我们开启一个线程,用来不断接收来自客户端发来的消息。
使用函数ReceiveMsg()函数来开启这个线程。这个函数中包括一个while循环,只要连接没有断开,就接收来自客户端的消息。
Socket.Receive(…)函数和Socket.Accept()一样,如果客户端没有发来消息就会卡在那里,知道客户端发来消息。
这里使用Socket.Poll(10, SelectMode.SelectRead)来判断有没有断开连接。它的意思是:如果连续10ms都无法读取就返回true。
客户端传过来的消息我们要用一个byte数组去接。然后将其转码成String以便输出查看。如果不查看的话这里是没必要转码成String的,因为我们马上就要把这个客户端发来的消息再广播出去。我们要把一个客户端发来的消息再传递给所有客户端,包括它自己。这里需要我们在主类里写一个静态成员函数BroadcastMsg(string msg)

static public void BroadcastMsg(string msg)
        {
            List<Client> unConnected = new List<Client>();
            foreach(var c in clientList)
            {
                if (c.isConnected)//只向保持连接的客户端发送消息
                {
                    //Console.WriteLine("Broadcasting a message");
                    c.SendMsg(msg);
                    //Console.WriteLine("Broadcasting succeed");
                }
                else//若没有连接则将它放入一个临时队列准备剔除
                    unConnected.Add(c);
            }
            foreach(var u in unConnected)//剔除断开连接的客户端
            {
                clientList.Remove(u);
                Console.WriteLine("A client is disconnected");
            }
        }

在BroadcastMsg(string msg)函数中我们遍历客户端对象链表中的每一个对象,调用他们的Client.SendMsg(string msg)函数。如果不需要测试的话,这里传一个byte数组就好了。在Client.SendMsg(string msg)函数中我们会调用Socket.Send(byte[] data)函数,将消息发送给客户端。

自此,服务器端大功告成。

总结,其实总体的流程就是
1.创建一个socket对象ServerSocket
2.将Server绑定一个ip和端口号
3.调用ServerSocket.Listen(…)函数开始监听
4.调用ServerSocket.Accept()函数接收一个客户端的连接请求,建立连接,获得客户端Socket对象ClientSocket
5.调用ClientSocket.receive(byte[])函数接收客户端发来的消息
6.调用ClientSocket.send(byte[])函数向客户端发送消息。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值