C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能
因?yàn)檫@段時(shí)間在學(xué)習(xí)Socket,所以就試著寫(xiě)了一個(gè)簡(jiǎn)單的聊天室。主要分為服務(wù)器端和多個(gè)客戶端。利用服務(wù)器端作數(shù)據(jù)中轉(zhuǎn)站,實(shí)現(xiàn)消息群發(fā)。
1、服務(wù)器端有兩個(gè)類(lèi):
using System.Collections.Generic; using System.Net; using System.Net.Sockets; namespace 聊天室_Socket_TCP_服務(wù)器端 { ? ? class Program ? ? { ? ? ? ? static List<Client> clients = new List<Client>(); ? ? ? ? static List<Client> notClients = new List<Client>(); ? ? ? ? /// <summary> ? ? ? ? /// 廣播消息 ? ? ? ? /// </summary> ? ? ? ? /// <param name="message"></param> ? ? ? ? public static void CastMessageTOAllConnetedClients(string message) ? ? ? ? { ? ? ? ? ? ? foreach (var client in clients) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? if (client.Conneted) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? client.CastMessage(message); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? else ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? notClients.Add(client); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? foreach (var temp in notClients) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? clients.Remove(temp); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? static void Main(string[] args) ? ? ? ? { ? ? ? ?? ? ? ? ? ? ? Socket tcpSever = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ? ? ? ? ? ? tcpSever.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 8899)); ? ? ? ? ? ? tcpSever.Listen(100);//監(jiān)聽(tīng)是否有客戶端發(fā)起連接 ? ? ? ? ? ? Console.WriteLine("Begin to listen..."); ? ? ? ? ? ? while (true) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? Socket clientSocket = tcpSever.Accept(); ? ? ? ? ? ? ? ? if (clientSocket!=null) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? Console.WriteLine("A client has connneted..."); ? ? ? ? ? ? ? ? ? ? Client client = new Client(clientSocket);//將每個(gè)新創(chuàng)建的連接通信放于client類(lèi)做通信 ? ? ? ? ? ? ? ? ? ? clients.Add(client); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? Console.ReadKey(); ? ? ? ? } ? ? } }
using System; using System.Net.Sockets; using System.Text; using System.Threading; namespace 聊天室_Socket_TCP_服務(wù)器端 { ? ? /// <summary> ? ? /// 利用該類(lèi)和客戶端做通信 ? ? /// </summary> ? ? class Client ? ? { ? ? ? ? public Socket clientSocket; ? ? ? ? private Thread mesManageTherad;? ? ? ? ? private byte[] bufffer=new byte[20]; ? ? ? ? public Client(Socket soc) ? ? ? ? { ? ? ? ? ? ? clientSocket = soc; ? ? ? ? ? ? //由于消息是不斷發(fā)送的,需要多次進(jìn)行處理。這里開(kāi)一個(gè)線程,專(zhuān)門(mén)用來(lái)處理消息。 ? ? ? ? ? ? mesManageTherad = new Thread(MessageSendFromClient); ? ? ? ? ? ? mesManageTherad.Start(); ? ? ? ? } ? ? ? ? private void MessageSendFromClient() ? ? ? ? { ? ? ? ? ? ? //開(kāi)啟的線程一直檢測(cè)客戶端客戶端發(fā)過(guò)來(lái)的消息 ? ? ? ? ? ? while (true) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? //判斷連接是否斷開(kāi), ?SelectMode.SelectRead讀狀態(tài)模式。 ? ? ? ? ? ? ? ? //poll已斷開(kāi)返回true ? ? ? ? ? ? ? ? if (clientSocket.Poll(10,SelectMode.SelectRead)==true) ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? clientSocket.Close(); ? ? ? ? ? ? ? ? ? ? break;//終止本線程 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? int byteNum = clientSocket.Receive(bufffer);//從客戶端接受消息 ? ? ? ? ? ? ? ? ? ? string mes = Encoding.UTF8.GetString(bufffer, 0 , byteNum); ? ? ? ? ? ? ? ? ? ? Console.WriteLine("客戶端發(fā)送過(guò)來(lái)的消息:"+mes); ? ? ? ? ? ? ? ? ? ? //廣播消息出去給每個(gè)客戶端 ? ? ? ? ? ? ? ? ? ? Program.CastMessageTOAllConnetedClients(mes);//對(duì)CastMessage的一層封裝 ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? /// <summary> ? ? ? ? /// Send messages to Clients ? ? ? ? /// </summary> ? ? ? ? public void CastMessage(string message) ? ? ? ? { ? ? ? ? ? ? byte[] data = Encoding.UTF8.GetBytes(message); ? ? ? ? ? ? clientSocket.Send(data); ? ? ? ? } ? ? ? ? /// <summary> ? ? ? ? /// 判斷是否斷開(kāi)連接 ? ? ? ? /// </summary> ? ? ? ? public bool Conneted ? ? ? ? { ? ? ? ? ? ? get ? ? ? ? ? ? { ? ? ? ? ? ? ? ? return clientSocket.Connected; ? ? ? ? ? ? } ? ? ? ? } ? ? } }
服務(wù)器端邏輯:
這里的服務(wù)器主要負(fù)責(zé)建立連接,接受客戶端消息,廣播客戶端發(fā)來(lái)的消息。
服務(wù)器通過(guò)socket對(duì)象綁定服務(wù)器IP和相應(yīng)端口號(hào)(端口號(hào)自己開(kāi),沒(méi)有被其他軟件占用就好),通過(guò)Listen監(jiān)聽(tīng)和服務(wù)器socket對(duì)象的Accept方法捕捉連接到服務(wù)器的客戶端socket,將捕捉到的客戶端socket放入List集合中方便統(tǒng)一管理和后面的消息群發(fā)。
關(guān)于捕捉到的客戶端socket的邏輯處理放在了Client類(lèi)中統(tǒng)一管理。
Client類(lèi)將收到客戶端的消息進(jìn)行接受,在Client中開(kāi)啟一個(gè)線程用于不斷得檢測(cè)是否有新消息從客戶端發(fā)送過(guò)來(lái),若有消息發(fā)送過(guò)來(lái)則通過(guò)CastMessageTOAllConnetedClients方法(對(duì)socket對(duì)象的Send方法的封裝)發(fā)送給每一個(gè)客戶端。
2.客戶端
客戶端是在Unity中使用NGUI插件簡(jiǎn)單開(kāi)發(fā)的一個(gè)聊天界面。把腳本掛在NGUI控件上即可??蛻舳酥饕?fù)責(zé)顯示消息,發(fā)送消息,接收消息。
using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; public class ChatManager : MonoBehaviour { ? ? private string _ipAdress = "192.168.1.2"; ? ? private int _port=8899; ? ? EndPoint remotPoint; ? ? Socket clientSocket; ? ? public UIInput buttonInput; ? ? private bool isCanSend=false; ? ? private string buttonMessage=null; ? ? Thread receiveThread; ? ? byte[] bufferReceive = new byte[1024]; ? ? public UILabel chatWindowLable; ? ? private string message = "";//默認(rèn)為空串 ? ? // Use this for initialization ? ? void Start () { ? ? ? ? ConnetToSever(_ipAdress, _port);//與服務(wù)器建立連接 ? ? } ? ? // Update is called once per frame ? ? void Update () { ? ? ? ? if (message!=null&&message!="") ? ? ? ? { ? ? ? ? ? ? chatWindowLable.text += "\n" + message; ? ? ? ? ? ? message = "";//清空消息 ? ? ? ? } ? ? } ? ? void ConnetToSever(string ipadress,int port) ? ? { ? ? ? ? clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ? ? ? ? remotPoint = new IPEndPoint(IPAddress.Parse(ipadress),port); ? ? ? ? //建立連接 ? ? ? ? clientSocket.Connect(remotPoint); ? ? ? ? //因?yàn)槭且恢痹跍?zhǔn)備接受的狀態(tài),所以開(kāi)啟一個(gè)線程來(lái)負(fù)責(zé)處理接受消息 ? ? ? ? receiveThread = new Thread(ReceiveMessageFormSever); ? ? ? ? receiveThread.Start(); ? ? } ? ? private new void SendMessage(string message) ? ? { ? ? ? ? byte [] buffer= Encoding.UTF8.GetBytes(message); ? ? ? ? clientSocket.SendTo(buffer,remotPoint); ? ? } ? ? public void OnSendButtonClickS() ? ? { ? ? ? ? if (buttonInput.value!=null) ? ? ? ? { ? ? ? ? ? ? buttonMessage = buttonInput.value; ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? buttonMessage = "輸入框?yàn)榭眨?; ? ? ? ? } ? ? ? ? SendMessage(buttonMessage); ? ? ? ? buttonInput.value = ""; ? ? } ? ? private void ReceiveMessageFormSever() ? ? { ? ? ? ? while (true) ? ? ? ? { ? ? ? ? ? ? if (clientSocket.Connected) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? int length = clientSocket.Receive(bufferReceive); ? ? ? ? ? ? ? ? message = Encoding.UTF8.GetString(bufferReceive, 0, length); ? ? ? ? ? ? ? ? //ps:不要在單獨(dú)的線程里面操作unity組件 ? ? ? ? ? ? } ? ? ? ? ? ? else ? ? ? ? ? ? { ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? } }
在客戶端中同樣有一個(gè)socket對(duì)象,這個(gè)對(duì)象通過(guò)ConnetToSever方法連接到服務(wù)器。在這里,假如某個(gè)客戶端通過(guò)輸入框輸入文本被客戶端腳本捕捉,它將以流的方式發(fā)送到服務(wù)器,服務(wù)器接受到文本,并在服務(wù)器端將文本群發(fā)至每個(gè)客戶端。服務(wù)器開(kāi)設(shè)了一個(gè)線程專(zhuān)門(mén)用于捕捉客戶端發(fā)來(lái)的消息,當(dāng)然,客戶端也有相應(yīng)的線程時(shí)刻捕捉服務(wù)器發(fā)來(lái)的消息。消息被客戶端捕捉到了,就可以顯示在各自的客戶端界面上了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C# 使用相同權(quán)限調(diào)用 cmd 傳入命令的方法
本文告訴大家如何使用相同權(quán)限調(diào)用cmd并且傳入命令,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07WPF如何自定義ProgressBar滾動(dòng)條樣式
這篇文章主要給大家介紹了關(guān)于WPF如何自定義ProgressBar滾動(dòng)條樣式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用WPF具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06C# 使用 WebBrowser 實(shí)現(xiàn) HTML 轉(zhuǎn)圖片功能的示例代碼
這篇文章主要介紹了C# 如何使用 WebBrowser 實(shí)現(xiàn) HTML 轉(zhuǎn)圖片功能,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07.NET/C#實(shí)現(xiàn)識(shí)別用戶訪問(wèn)設(shè)備的方法
這篇文章主要介紹了.NET/C#實(shí)現(xiàn)識(shí)別用戶訪問(wèn)設(shè)備的方法,結(jié)合實(shí)例形式分析了C#識(shí)別用戶訪問(wèn)設(shè)備的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02C#獲取變更過(guò)的DataTable記錄的實(shí)現(xiàn)方法
這篇文章主要介紹了C#獲取變更過(guò)的DataTable記錄的實(shí)現(xiàn)方法,對(duì)初學(xué)者很有學(xué)習(xí)借鑒價(jià)值,需要的朋友可以參考下2014-08-08C#.NET采用HTML模板發(fā)送電子郵件完整實(shí)例
這篇文章主要介紹了C#.NET采用HTML模板發(fā)送電子郵件的方法,主要包括了HTML模板、替換函數(shù)與郵件函數(shù)三部分,是非常實(shí)用的功能,需要的朋友可以參考下2014-09-09c# 使用模式匹配以及 is 和 as 運(yùn)算符安全地進(jìn)行強(qiáng)制轉(zhuǎn)換
這篇文章主要介紹了c# 使用模式匹配以及 is 和 as 運(yùn)算符安全地進(jìn)行強(qiáng)制轉(zhuǎn)換,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-10-10