C#使用Socket實現伺服器與多個客戶端通訊(簡單的聊天系統)
阿新 • • 發佈:2020-02-13
擴充套件:
由於server端是儲存了所有server與client的連線物件,因此我們是可以基於此demo的基礎上實現聊天系統:
* 每當一個與使用者發言時,是由server接收到的某個使用者的發言資訊的,此時伺服器端可以通過迴圈傳送該使用者傳送的資訊給每個已經連線連線的使用者(排除傳送者)。
Server端程式碼:
class Program { //建立一個和客戶端通訊的套接字 static Socket SocketWatch = null; //定義一個集合,儲存客戶端資訊 static Dictionary<string,Socket> ClientConnectionItems = new Dictionary<string,Socket> { }; static void Main(string[] args) { //埠號(用來監聽的) int port = 6000; //string host = "127.0.0.1"; //IPAddress ip = IPAddress.Parse(host); IPAddress ip = IPAddress.Any; //將IP地址和埠號繫結到網路節點point上 IPEndPoint ipe = new IPEndPoint(ip,port); //定義一個套接字用於監聽客戶端發來的訊息,包含三個引數(IP4定址協議,流式連線,Tcp協議) SocketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); //監聽繫結的網路節點 SocketWatch.Bind(ipe); //將套接字的監聽佇列長度限制為20 SocketWatch.Listen(20); //負責監聽客戶端的執行緒:建立一個監聽執行緒 Thread threadwatch = new Thread(WatchConnecting); //將窗體執行緒設定為與後臺同步,隨著主執行緒結束而結束 threadwatch.IsBackground = true; //啟動執行緒 threadwatch.Start(); Console.WriteLine("開啟監聽......"); Console.WriteLine("點選輸入任意資料回車退出程式......"); Console.ReadKey(); SocketWatch.Close(); //Socket serverSocket = null; //int i=1; //while (true) //{ // //receive message // serverSocket = SocketWatch.Accept(); // Console.WriteLine("連線已經建立!"); // string recStr = ""; // byte[] recByte = new byte[4096]; // int bytes = serverSocket.Receive(recByte,recByte.Length,0); // //recStr += Encoding.ASCII.GetString(recByte,bytes); // recStr += Encoding.GetEncoding("utf-8").GetString(recByte,bytes); // //send message // Console.WriteLine(recStr); // Console.Write("請輸入內容:"); // string sendStr = Console.ReadLine(); // //byte[] sendByte = Encoding.ASCII.GetBytes(sendStr); // byte[] sendByte = Encoding.GetEncoding("utf-8").GetBytes(sendStr); // //Thread.Sleep(4000); // serverSocket.Send(sendByte,sendByte.Length,0); // serverSocket.Close(); // if (i >= 100) // { // break; // } // i++; //} //sSocket.Close(); //Console.WriteLine("連線關閉!"); //Console.ReadLine(); } //監聽客戶端發來的請求 static void WatchConnecting() { Socket connection = null; //持續不斷監聽客戶端發來的請求 while (true) { try { connection = SocketWatch.Accept(); } catch (Exception ex) { //提示套接字監聽異常 Console.WriteLine(ex.Message); break; } //客戶端網路結點號 string remoteEndPoint = connection.RemoteEndPoint.ToString(); //新增客戶端資訊 ClientConnectionItems.Add(remoteEndPoint,connection); //顯示與客戶端連線情況 Console.WriteLine("\r\n[客戶端\"" + remoteEndPoint + "\"建立連線成功! 客戶端數量:" + ClientConnectionItems .Count+ "]"); //獲取客戶端的IP和埠號 IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address; int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port; //讓客戶顯示"連線成功的"的資訊 string sendmsg = "[" + "本地IP:" + clientIP + " 本地埠:" + clientPort.ToString() + " 連線服務端成功!]"; byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg); connection.Send(arrSendMsg); //建立一個通訊執行緒 Thread thread = new Thread(recv); //設定為後臺執行緒,隨著主執行緒退出而退出 thread.IsBackground = true; //啟動執行緒 thread.Start(connection); } } /// <summary> /// 接收客戶端發來的資訊,客戶端套接字物件 /// </summary> /// <param name="socketclientpara"></param> static void recv(object socketclientpara) { Socket socketServer = socketclientpara as Socket; while (true) { //建立一個記憶體緩衝區,其大小為1024*1024位元組 即1M byte[] arrServerRecMsg = new byte[1024 * 1024]; //將接收到的資訊存入到記憶體緩衝區,並返回其位元組陣列的長度 try { int length = socketServer.Receive(arrServerRecMsg); //將機器接受到的位元組陣列轉換為人可以讀懂的字串 string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg,length); //將傳送的字串資訊附加到文字框txtMsg上 Console.WriteLine("\r\n[客戶端:" + socketServer.RemoteEndPoint + " 時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")+ "]\r\n" + strSRecMsg); //Thread.Sleep(3000); //socketServer.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:"+strSRecMsg)); //傳送客戶端資料 if (ClientConnectionItems.Count > 0) { foreach (var socketTemp in ClientConnectionItems) { socketTemp.Value.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:" + strSRecMsg)); } } } catch (Exception) { ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString()); //提示套接字監聽異常 Console.WriteLine("\r\n[客戶端\"" + socketServer.RemoteEndPoint + "\"已經中斷連線! 客戶端數量:" + ClientConnectionItems.Count+"]"); //關閉之前accept出來的和客戶端進行通訊的套接字 socketServer.Close(); break; } } } }
Client端程式碼:
class Program { //建立1個客戶端套接字和1個負責監聽服務端請求的執行緒 static Thread ThreadClient = null; static Socket SocketClient = null; static void Main(string[] args) { try { int port = 6000; string host = "127.0.0.1";//伺服器端ip地址 IPAddress ip = IPAddress.Parse(host); IPEndPoint ipe = new IPEndPoint(ip,port); //定義一個套接字監聽 SocketClient = new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp); try { //客戶端套接字連線到網路節點上,用的是Connect SocketClient.Connect(ipe); } catch (Exception) { Console.WriteLine("連線失敗!\r\n"); Console.ReadLine(); return; } ThreadClient = new Thread(Recv); ThreadClient.IsBackground = true; ThreadClient.Start(); Thread.Sleep(1000); Console.WriteLine("請輸入內容<按Enter鍵傳送>:\r\n"); while(true) { string sendStr = Console.ReadLine(); ClientSendMsg(sendStr); } //int i = 1; //while (true) //{ // Console.Write("請輸入內容:"); // string sendStr = Console.ReadLine(); // Socket clientSocket = new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp); // clientSocket.Connect(ipe); // //send message // //byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr); // byte[] sendBytes = Encoding.GetEncoding("utf-8").GetBytes(sendStr); // //Thread.Sleep(4000); // clientSocket.Send(sendBytes); // //receive message // string recStr = ""; // byte[] recBytes = new byte[4096]; // int bytes = clientSocket.Receive(recBytes,recBytes.Length,0); // //recStr += Encoding.ASCII.GetString(recBytes,bytes); // recStr += Encoding.GetEncoding("utf-8").GetString(recBytes,bytes); // Console.WriteLine(recStr); // clientSocket.Close(); // if (i >= 100) // { // break; // } // i++; //} //Console.ReadLine(); //return; //string result = String.Empty; } catch (Exception ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } } //接收服務端發來資訊的方法 public static void Recv() { int x = 0; //持續監聽服務端發來的訊息 while (true) { try { //定義一個1M的記憶體緩衝區,用於臨時性儲存接收到的訊息 byte[] arrRecvmsg = new byte[1024 * 1024]; //將客戶端套接字接收到的資料存入記憶體緩衝區,並獲取長度 int length = SocketClient.Receive(arrRecvmsg); //將套接字獲取到的字元陣列轉換為人可以看懂的字串 string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg,length); if (x == 1) { Console.WriteLine("\r\n伺服器:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n" + strRevMsg+"\r\n"); } else { Console.WriteLine(strRevMsg + "\r\n"); x = 1; } } catch (Exception ex) { Console.WriteLine("遠端伺服器已經中斷連線!" + ex.Message + "\r\n"); break; } } } //傳送字元資訊到服務端的方法 public static void ClientSendMsg(string sendMsg) { //將輸入的內容字串轉換為機器可以識別的位元組陣列 byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg); //呼叫客戶端套接字傳送位元組陣列 SocketClient.Send(arrClientSendMsg); } }
測試結果:
server端:
client端:
程式碼下載地址:C-Socket_jb51.zip
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。