基于c#用Socket做一個局域網(wǎng)聊天工具
程序設(shè)計成為簡單的服務(wù)端和客戶端之間的通信, 但通過一些方法可以將這兩者進行統(tǒng)一起來, 讓服務(wù)端也成為客戶端, 讓客戶端也成為服務(wù)端, 使它們之間可以互相隨時不間斷的通信. 考慮到實現(xiàn)最原始的服務(wù)端和客戶端之間的通信所需要的步驟對于寫這樣的程序是很有幫助的.
作為服務(wù)端, 要聲明一個Socket A并綁定(Bind)某一個IP+這個IP指定的通信端口, 比如這個是127.0.0.1:9050, 然后開始監(jiān)聽(Listen), Listen可以監(jiān)聽來自多個IP傳過來的連接請求, 具體可以同時連接幾個客戶端, Listen方法中可以設(shè)定一個參數(shù). 如果Listen到某一個客戶端發(fā)來連接請求了, 這時定義一個新的Socket B專門負責(zé)與這個客戶端的通信, Socket B = A.Accept(). 這時可以獲取這個客戶端的IP和端口, IPEndPoint C = (IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分別表示客戶端C的IP地址和端口. 這時通過B.Send()方法就可以給C發(fā)送消息了, B.Receive()可以接收客戶端C發(fā)來的信息.
作為客戶端, 也需要聲明一個Socket D并綁定某一個IP+本機一個未被占用的端口, 定義IPEndPoint E表示要進行連接的服務(wù)端Socket, 要指明E的IP和端口, 這樣才可以進行端口對端口之間的通信, 接下來就可以嘗試D.Connect(E), 連接成功之后就可以發(fā)送和接收數(shù)據(jù)了, D.Send(), D.Receive.
發(fā)送消息時, 數(shù)據(jù)都是以字節(jié)或字節(jié)數(shù)組為單位進行傳輸?shù)? 比如我客戶端D要發(fā)送"Hello World"則要這樣寫: D.Send(Encoding.ASCII.GetBytes("Hello World")). 接受消息時, 也是以字節(jié)或字節(jié)數(shù)組, 比如服務(wù)端要接受D剛才發(fā)送的Hello World, 可以這樣寫: Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); stringdata這時就是Hello World.
上面只是大概的闡述了服務(wù)端與客戶端之間的通信過程, 在網(wǎng)上找到了具體的代碼例子, 也貼過來參考參考. 這個例子沒有將服務(wù)端與客戶端統(tǒng)一起來, 他是分別寫服務(wù)端和客戶端的.
服務(wù)端代碼
using System;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpserver
{
/// <summary>
/// Class1 的摘要說明。
/// </summary>
class server
{
/// <summary>
/// 應(yīng)用程序的主入口點。
/// </summary>
[STAThread]
static void Main( string [] args)
{
//
// TODO: 在此處添加代碼以啟動應(yīng)用程序
//
int recv; // 用于表示客戶端發(fā)送的信息長度
byte [] data;// = new byte [ 1024 ]; // 用于緩存客戶端所發(fā)送的信息,通過socket傳遞的信息必須為字節(jié)數(shù)組
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050 ); // 本機預(yù)使用的IP和端口
Socket newsock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
newsock.Bind(ipep); // 綁定
newsock.Listen( 10 ); // 監(jiān)聽
Console.WriteLine( " waiting for a client " );
Socket client = newsock.Accept(); //當(dāng)有可用的客戶端連接嘗試時執(zhí)行,并返回一個新的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)來不斷的從客戶端獲取信息
data = new byte [ 1024 ];
recv = client.Receive(data);
Console.WriteLine( " recv= " + recv);
if (recv == 0 ) // 當(dāng)信息長度為0,說明客戶端連接斷開
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 的摘要說明。
/// </summary>
class client
{
/// <summary>
/// 應(yīng)用程序的主入口點。
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: 在此處添加代碼以啟動應(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
{
// 因為客戶端只是用來向特定的服務(wù)器發(fā)送信息,所以不需要綁定本機的IP和端口。不需要監(jiān)聽。
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ù)端和客戶端都是控制臺應(yīng)用程序, 想辦法做一個窗體類型的, 思路就是另起一個線程, 這個線程專門負責(zé)兩端建立連接. 如果不采用另起線程的方法, 當(dāng)?shù)却B接而沒有連接上, 或者主動連接, 服務(wù)端還沒有相應(yīng)時, 程序就會出現(xiàn)沒有響應(yīng)的假死狀態(tài).
當(dāng)這個線程將兩個端口連接成功后, 就讓程序進入一個死循環(huán), 這個死循環(huán)負責(zé)不斷的接收是否有消息傳來, 傳來的話就在txtGetMsg中顯示出來:
while (true) // 用死循環(huán)來不斷的獲取信息
{
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中的文本, 我寫的是用Unicode編碼, 所以可以發(fā)送中文字符.
private void btnSendMsg_Click(object sender, EventArgs e)
{
string input = txtSendMsg.Text;
if (input == "")
{
MessageBox.Show("消息不能為空!", "發(fā)送消息出錯");
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 = "";
}
}
}
程序的運行效果:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
欄 目:C#教程
下一篇:C#中常用的正則表達式實例
本文標(biāo)題:基于c#用Socket做一個局域網(wǎng)聊天工具
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6216.html
您可能感興趣的文章
- 01-10C#實現(xiàn)判斷當(dāng)前操作用戶管理角色的方法
- 01-10C#使用Dispose模式實現(xiàn)手動對資源的釋放
- 01-10C#3.0使用EventLog類寫Windows事件日志的方法
- 01-10C#調(diào)用dos窗口獲取相關(guān)信息的方法
- 01-10C#中DataGridView常用操作實例小結(jié)
- 01-10C#實現(xiàn)讀取被進程占用的文件實現(xiàn)方法
- 01-10C#禁用雙擊窗體圖標(biāo)關(guān)閉窗體的方法
- 01-10C#使用windows服務(wù)開啟應(yīng)用程序的方法
- 01-10C#線程隊列用法實例分析
- 01-10C#利用反射技術(shù)實現(xiàn)去掉按鈕選中時的邊框效果


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機閱讀
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實例總結(jié)
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置


