基于c#用Socket做一個(gè)局域網(wǎng)聊天工具
程序設(shè)計(jì)成為簡(jiǎn)單的服務(wù)端和客戶端之間的通信, 但通過(guò)一些方法可以將這兩者進(jìn)行統(tǒng)一起來(lái), 讓服務(wù)端也成為客戶端, 讓客戶端也成為服務(wù)端, 使它們之間可以互相隨時(shí)不間斷的通信. 考慮到實(shí)現(xiàn)最原始的服務(wù)端和客戶端之間的通信所需要的步驟對(duì)于寫(xiě)這樣的程序是很有幫助的.
作為服務(wù)端, 要聲明一個(gè)Socket A并綁定(Bind)某一個(gè)IP+這個(gè)IP指定的通信端口, 比如這個(gè)是127.0.0.1:9050, 然后開(kāi)始監(jiān)聽(tīng)(Listen), Listen可以監(jiān)聽(tīng)來(lái)自多個(gè)IP傳過(guò)來(lái)的連接請(qǐng)求, 具體可以同時(shí)連接幾個(gè)客戶端, Listen方法中可以設(shè)定一個(gè)參數(shù). 如果Listen到某一個(gè)客戶端發(fā)來(lái)連接請(qǐng)求了, 這時(shí)定義一個(gè)新的Socket B專門負(fù)責(zé)與這個(gè)客戶端的通信, Socket B = A.Accept(). 這時(shí)可以獲取這個(gè)客戶端的IP和端口, IPEndPoint C = (IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分別表示客戶端C的IP地址和端口. 這時(shí)通過(guò)B.Send()方法就可以給C發(fā)送消息了, B.Receive()可以接收客戶端C發(fā)來(lái)的信息.
作為客戶端, 也需要聲明一個(gè)Socket D并綁定某一個(gè)IP+本機(jī)一個(gè)未被占用的端口, 定義IPEndPoint E表示要進(jìn)行連接的服務(wù)端Socket, 要指明E的IP和端口, 這樣才可以進(jìn)行端口對(duì)端口之間的通信, 接下來(lái)就可以嘗試D.Connect(E), 連接成功之后就可以發(fā)送和接收數(shù)據(jù)了, D.Send(), D.Receive.
發(fā)送消息時(shí), 數(shù)據(jù)都是以字節(jié)或字節(jié)數(shù)組為單位進(jìn)行傳輸?shù)? 比如我客戶端D要發(fā)送"Hello World"則要這樣寫(xiě): D.Send(Encoding.ASCII.GetBytes("Hello World")). 接受消息時(shí), 也是以字節(jié)或字節(jié)數(shù)組, 比如服務(wù)端要接受D剛才發(fā)送的Hello World, 可以這樣寫(xiě): Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); stringdata這時(shí)就是Hello World.
上面只是大概的闡述了服務(wù)端與客戶端之間的通信過(guò)程, 在網(wǎng)上找到了具體的代碼例子, 也貼過(guò)來(lái)參考參考. 這個(gè)例子沒(méi)有將服務(wù)端與客戶端統(tǒng)一起來(lái), 他是分別寫(xiě)服務(wù)端和客戶端的.
服務(wù)端代碼
using System; using System; using System.Net; using System.Net.Sockets; using System.Text; namespace tcpserver { /// <summary> /// Class1 的摘要說(shuō)明。 /// </summary> class server { /// <summary> /// 應(yīng)用程序的主入口點(diǎn)。 /// </summary> [STAThread] static void Main( string [] args) { // // TODO: 在此處添加代碼以啟動(dòng)應(yīng)用程序 // int recv; // 用于表示客戶端發(fā)送的信息長(zhǎng)度 byte [] data;// = new byte [ 1024 ]; // 用于緩存客戶端所發(fā)送的信息,通過(guò)socket傳遞的信息必須為字節(jié)數(shù)組 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050 ); // 本機(jī)預(yù)使用的IP和端口 Socket newsock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); newsock.Bind(ipep); // 綁定 newsock.Listen( 10 ); // 監(jiān)聽(tīng) Console.WriteLine( " waiting for a client " ); Socket client = newsock.Accept(); //當(dāng)有可用的客戶端連接嘗試時(shí)執(zhí)行,并返回一個(gè)新的socket,用于與客戶端之間的通信 IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint; Console.WriteLine( " connect with client: " + clientip.Address + " at port: " + clientip.Port); string welcome = " welcome here! " ; data = Encoding.ASCII.GetBytes(welcome); client.Send(data,data.Length,SocketFlags.None); // 發(fā)送信息 while ( true ) { // 用死循環(huán)來(lái)不斷的從客戶端獲取信息 data = new byte [ 1024 ]; recv = client.Receive(data); Console.WriteLine( " recv= " + recv); if (recv == 0 ) // 當(dāng)信息長(zhǎng)度為0,說(shuō)明客戶端連接斷開(kāi) break ; Console.WriteLine(Encoding.ASCII.GetString(data, 0 ,recv)); client.Send(data,recv,SocketFlags.None); } Console.WriteLine( " Disconnected from " + clientip.Address); client.Close(); newsock.Close(); } } }
客戶端代碼
using System; using System.Net; using System.Net.Sockets; using System.Text; namespace tcpclient { /// <summary> /// Class1 的摘要說(shuō)明。 /// </summary> class client { /// <summary> /// 應(yīng)用程序的主入口點(diǎn)。 /// </summary> [STAThread] static void Main(string[] args) { // // TODO: 在此處添加代碼以啟動(dòng)應(yīng)用程序 // byte[] data = new byte[1024]; Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); newclient.Bind(new IPEndPoint(IPAddress.Any, 905)); Console.Write(" please input the server ip: "); string ipadd = Console.ReadLine(); Console.WriteLine(); Console.Write(" please input the server port: "); int port = Convert.ToInt32(Console.ReadLine()); IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port); // 服務(wù)器的IP和端口 try { // 因?yàn)榭蛻舳酥皇怯脕?lái)向特定的服務(wù)器發(fā)送信息,所以不需要綁定本機(jī)的IP和端口。不需要監(jiān)聽(tīng)。 newclient.Connect(ie); } catch (SocketException e) { Console.WriteLine(" unable to connect to server "); Console.WriteLine(e.ToString()); return; } int receivedDataLength = newclient.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); Console.WriteLine(stringdata); while (true) { string input = Console.ReadLine(); if (input == " exit ") break; newclient.Send(Encoding.ASCII.GetBytes(input)); data = new byte[1024]; receivedDataLength = newclient.Receive(data); stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); Console.WriteLine(stringdata); } Console.WriteLine(" disconnect from sercer "); newclient.Shutdown(SocketShutdown.Both); newclient.Close(); } } }
上面的服務(wù)端和客戶端都是控制臺(tái)應(yīng)用程序, 想辦法做一個(gè)窗體類型的, 思路就是另起一個(gè)線程, 這個(gè)線程專門負(fù)責(zé)兩端建立連接. 如果不采用另起線程的方法, 當(dāng)?shù)却B接而沒(méi)有連接上, 或者主動(dòng)連接, 服務(wù)端還沒(méi)有相應(yīng)時(shí), 程序就會(huì)出現(xiàn)沒(méi)有響應(yīng)的假死狀態(tài).
當(dāng)這個(gè)線程將兩個(gè)端口連接成功后, 就讓程序進(jìn)入一個(gè)死循環(huán), 這個(gè)死循環(huán)負(fù)責(zé)不斷的接收是否有消息傳來(lái), 傳來(lái)的話就在txtGetMsg中顯示出來(lái):
while (true) // 用死循環(huán)來(lái)不斷的獲取信息 { data = new byte[1024]; recv = newclient.Receive(data); uiContext.Send(new SendOrPostCallback( state => { int txtGetMsgLength = txtGetMsg.Text.Length; string recMsg = "Friend: " + System.DateTime.Now.ToString() + "\n " +Encoding.Unicode.GetString(data, 0, recv) + "\n"; txtGetMsg.AppendText(recMsg); txtGetMsg.Select(txtGetMsgLength, recMsg.Length - Encoding.Unicode.GetString(data, 0, recv).Length - 1); txtGetMsg.SelectionColor = Color.Red; }), null); }
如果按下發(fā)送消息的按鈕, 則發(fā)送txtSendMsg中的文本, 我寫(xiě)的是用Unicode編碼, 所以可以發(fā)送中文字符.
private void btnSendMsg_Click(object sender, EventArgs e) { string input = txtSendMsg.Text; if (input == "") { MessageBox.Show("消息不能為空!", "發(fā)送消息出錯(cuò)"); txtSendMsg.Focus(); } else { if (meIsClient) { newclient.Send(Encoding.Unicode.GetBytes(input)); string showText = "Me: " + System.DateTime.Now.ToString() + "\n " + input + "\n"; int txtGetMsgLength = txtGetMsg.Text.Length; txtGetMsg.AppendText(showText); txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length); txtGetMsg.SelectionColor = Color.Blue; txtSendMsg.Text = ""; } else { client.Send(Encoding.Unicode.GetBytes(input)); string showText = "Me " + System.DateTime.Now.ToString() + "\n " + input + "\n"; int txtGetMsgLength = txtGetMsg.Text.Length; txtGetMsg.AppendText(showText); txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length); txtGetMsg.SelectionColor = Color.Blue; txtSendMsg.Text = ""; } } }
程序的運(yùn)行效果:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C#使用WebSocket實(shí)現(xiàn)聊天室功能
- C#使用Socket實(shí)現(xiàn)本地多人聊天室
- C#基于Socket實(shí)現(xiàn)多人聊天功能
- c#基于WinForm的Socket實(shí)現(xiàn)簡(jiǎn)單的聊天室 IM
- C# Socket編程實(shí)現(xiàn)簡(jiǎn)單的局域網(wǎng)聊天器的示例代碼
- C#使用Socket實(shí)現(xiàn)服務(wù)器與多個(gè)客戶端通信(簡(jiǎn)單的聊天系統(tǒng))
- C#使用Socket實(shí)現(xiàn)局域網(wǎng)聊天
- 分享一個(gè)C#編寫(xiě)簡(jiǎn)單的聊天程序(詳細(xì)介紹)
- C#制作簡(jiǎn)單的多人在線即時(shí)交流聊天室
- C#用websocket實(shí)現(xiàn)簡(jiǎn)易聊天功能(服務(wù)端)
相關(guān)文章
Unity給物體添加多個(gè)Tag的實(shí)現(xiàn)
這篇文章主要介紹了Unity給物體添加多個(gè)Tag的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04c# 利用易福門振動(dòng)模塊VSE002采集振動(dòng)數(shù)據(jù)的方法
這篇文章主要介紹了c# 利用易福門振動(dòng)模塊VSE002采集振動(dòng)數(shù)據(jù)的方法,本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04C#基于FTP協(xié)議的簡(jiǎn)易軟件自動(dòng)升級(jí)程序
這篇文章主要為大家詳細(xì)介紹了C#基于FTP協(xié)議的簡(jiǎn)易軟件自動(dòng)升級(jí)程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03C# Oracle批量插入數(shù)據(jù)進(jìn)度條的實(shí)現(xiàn)代碼
這篇文章主要介紹了C# Oracle批量插入數(shù)據(jù)進(jìn)度條的實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-04-04