C#聊天程序服務(wù)端與客戶端完整實(shí)例代碼
本文所述為基于C#實(shí)現(xiàn)的多人聊天程序服務(wù)端與客戶端完整代碼。本實(shí)例省略了結(jié)構(gòu)定義部分,服務(wù)端主要是邏輯處理部分代碼,因此使用時(shí)需要完善一些窗體按鈕之類的。
先看服務(wù)端代碼如下:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace 多人聊天程序Server端
{
/// <summary>
/// 應(yīng)用程序的主入口點(diǎn)。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
// 啟動(dòng)服務(wù)按鈕
private void button2_Click(object sender, System.EventArgs e)
{
try
{
// 必須填寫端口
if(txtPort.Text == "")
{
MessageBox.Show("請(qǐng)先填寫服務(wù)端口號(hào)!", "提示");
return;
}
Int32 port = Int32.Parse(txtPort.Text); // 獲得端口號(hào)
// 創(chuàng)建偵聽的Socket
mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
// 將 Socket 綁定到本地的終結(jié)點(diǎn)上
mainSocket.Bind(localEP);
// 開始偵聽,最大的連接數(shù)是 5
mainSocket.Listen(5);
// 開始一個(gè)異步操作接受客戶的連接請(qǐng)求
mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
// 啟動(dòng)服務(wù)按鈕不可用,停止服務(wù)按鈕可用
UpdateControls(true);
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 更新“啟動(dòng)服務(wù)按鈕”和“停止服務(wù)”按鈕的狀態(tài):是否可用;
// 注意:兩個(gè)按鈕的狀態(tài)是互斥的
private void UpdateControls(bool onServe)
{
button2.Enabled = !onServe;
button3.Enabled = onServe;
if(onServe)
{
status.Text = "已啟動(dòng)服務(wù)";
}
else
{
status.Text = "未啟動(dòng)服務(wù)";
}
}
// 回調(diào)函數(shù),當(dāng)客戶連接上時(shí),將會(huì)被調(diào)用
public void OnClientConnect(IAsyncResult asyn)
{
try
{
// 調(diào)用EndAccept完成BeginAccept異步調(diào)用,返回一個(gè)新的Socket處理與客戶的通信
Socket workerSocket = mainSocket.EndAccept(asyn);
// 增加客戶數(shù)目
Interlocked.Increment(ref clientNum);
// 將 workerSocket Socket加入到 ArrayList 中
workerSocketList.Add(workerSocket);
// 發(fā)送歡迎信息給連接上服務(wù)器的客戶
string msg = "歡迎客戶 " + clientNum + " 登錄服務(wù)器\n";
SendWelcomeToClient(msg, clientNum);
// 在線客戶數(shù)目改變,必須更新客戶列表
UpdateClientListControl();
// 連接上的客戶接收數(shù)據(jù)
WaitForData(workerSocket, clientNum);
// 主 Socket 返回,繼續(xù)等待其它的連接請(qǐng)求
mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch(ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket已經(jīng)關(guān)閉!\n");
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 發(fā)送歡迎信息給客戶
void SendWelcomeToClient(string msg, int clientNumber)
{
// 用UTF8格式來將string信息轉(zhuǎn)化成byte數(shù)組形式
byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
// 獲得客戶clientNumber對(duì)應(yīng)的Socket
Socket workerSocket = (Socket)workerSocketList[clientNumber - 1];
// 將數(shù)據(jù)發(fā)給客戶
workerSocket.Send(byData);
}
// 該類保存當(dāng)前的socket,它的客戶號(hào)還有發(fā)送給服務(wù)器的數(shù)據(jù)
public class SocketPacket
{
public System.Net.Sockets.Socket currentSocket; // 當(dāng)前的Socket
public int clientNumber; // 客戶號(hào)
public byte[] dataBuffer = new byte[1024]; // 發(fā)給服務(wù)器的數(shù)據(jù)
// 構(gòu)造函數(shù)
public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)
{
currentSocket = socket;
this.clientNumber = clientNumber;
}
}
// 開始等待客戶發(fā)送數(shù)據(jù)
public void WaitForData(System.Net.Sockets.Socket socket, int clientNumber)
{
try
{
if(pfnWorkerCallBack == null)
{
// 當(dāng)連接上的客戶有寫的操作的時(shí)候,調(diào)用回調(diào)函數(shù)
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
}
SocketPacket socketPacket = new SocketPacket(socket, clientNumber);
socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
SocketFlags.None, pfnWorkerCallBack, socketPacket);
}
catch(SocketException se)
{
MessageBox.Show (se.Message, "提示");
}
}
// 當(dāng)客戶寫數(shù)據(jù)時(shí),調(diào)用以下方法
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState ;
try
{
// EndReceive完成BeginReceive異步調(diào)用,返回客戶寫入流的字節(jié)數(shù)
int iRx = socketData.currentSocket.EndReceive(asyn);
// 加 1 是因?yàn)樽址?'\0' 作為結(jié)束標(biāo)志符
char[] chars = new char[iRx + 1];
// 對(duì)客戶發(fā)來的信息進(jìn)行UTF8解碼,存入chars字符數(shù)組中
System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
int charLen = decoder.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
string msg = "客戶 " + socketData.clientNumber + " 發(fā)的信息:" + szData;
// 將客戶發(fā)的數(shù)據(jù)加入到信息列表中
AppendToRichEditControl(msg);
// 等待數(shù)據(jù)
WaitForData(socketData.currentSocket, socketData.clientNumber);
}
catch (ObjectDisposedException )
{
System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket已經(jīng)關(guān)閉!\n");
}
catch(SocketException se)
{
if(se.ErrorCode == 10054)
{
// 將客戶斷開連接的信息寫入信息列表中
string msg = "客戶 " + socketData.clientNumber + " 已斷開了連接!" + "\n";
AppendToRichEditControl(msg);
// 移走已關(guān)閉的socket
workerSocketList[socketData.clientNumber - 1] = null;
// 更新客戶列表
UpdateClientListControl();
}
else
{
MessageBox.Show (se.Message, "提示");
}
}
}
// 更新信息列表,該方法可由主線程或其他工作線程所調(diào)用
private void AppendToRichEditControl(string msg)
{
// 測(cè)試看是哪個(gè)線程調(diào)用了該方法
if (InvokeRequired)
{
// We cannot update the GUI on this thread.
// All GUI controls are to be updated by the main (GUI) thread.
// Hence we will use the invoke method on the control which will
// be called when the Main thread is free
// Do UI update on UI thread
object[] pList = {msg};
txtRecvMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);
}
else
{
// 創(chuàng)建該控件的主線程直接更新信息列表
OnUpdateRichEdit(msg);
}
}
// 添加信息到 txtRecvMsg 中
private void OnUpdateRichEdit(string msg)
{
// txtRecvMsg.AppendText(msg);
txtRecvMsg.Text = txtRecvMsg.Text + msg;
}
// 更新客戶列表
private void UpdateClientListControl()
{
if (InvokeRequired) // Is this called from a thread other than the one created
// the control
{
clientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null);
}
else
{
// 創(chuàng)建該控件的主線程直接更新信息列表
UpdateClientList();
}
}
// 更新客戶列表
void UpdateClientList()
{
clientList.Items.Clear(); // 清空客戶列表
for(int i = 0; i < workerSocketList.Count; i++)
{
// 加1,是因?yàn)閿?shù)組從下標(biāo)0開始,而我們的客戶標(biāo)號(hào)是從1開始
string clientKey = Convert.ToString(i + 1);
Socket workerSocket = (Socket)workerSocketList[i];
if(workerSocket != null)
{
// 將連接著服務(wù)器的客戶添加到客戶列表中
if(workerSocket.Connected)
{
clientList.Items.Add(clientKey);
}
}
}
}
// 停止服務(wù)按鈕
private void button3_Click(object sender, System.EventArgs e)
{
CloseSockets();
UpdateControls(false);
// 更新客戶列表
UpdateClientListControl();
}
// 發(fā)送信息按鈕
private void button1_Click(object sender, System.EventArgs e)
{
// 如果在線客戶列表不為空,則允許發(fā)送信息
if (clientList.Items.Count != 0 )
{
try
{
string msg = txtSendMsg.Text;
msg = "服務(wù)器信息: " + msg + "\n";
byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
Socket workerSocket = null;
for(int i = 0; i < workerSocketList.Count; i++)
{
workerSocket = (Socket)workerSocketList[i];
if(workerSocket!= null)
{
// 發(fā)給所有連接上服務(wù)器的客戶
if(workerSocket.Connected)
{
workerSocket.Send(byData);
}
}
}
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
else
{
MessageBox.Show("沒有在線客戶,不能發(fā)送信息!", "提示");
}
}
// 清空信息按鈕
private void button4_Click(object sender, System.EventArgs e)
{
txtRecvMsg.Clear(); // 清空從客戶發(fā)來的信息
}
// 關(guān)閉窗體按鈕
private void button5_Click(object sender, System.EventArgs e)
{
CloseSockets();
Close();
}
// 關(guān)閉Socket
void CloseSockets()
{
// 關(guān)閉主Socket
if(mainSocket != null)
{
mainSocket.Close();
}
Socket workerSocket = null;
// 關(guān)閉客戶 Socket 數(shù)組
for(int i = 0; i < workerSocketList.Count; i++)
{
workerSocket = (Socket)workerSocketList[i];
if(workerSocket != null)
{
workerSocket.Close();
workerSocket = null;
}
}
}
private void Form1_Load(object sender, System.EventArgs e)
{
try
{
// 獲得本機(jī)的IP地址
txtIP.Text = Dns.Resolve(Dns.GetHostName()).AddressList[0].ToString();
// 啟動(dòng)時(shí),啟動(dòng)服務(wù)按鈕可用,停止服務(wù)按鈕不可用
UpdateControls(false);
}
catch(Exception exc)
{
MessageBox.Show(exc.Message, "提示");
}
}
}
}
客戶端主要實(shí)現(xiàn)接收來自服務(wù)端返回的消息、實(shí)現(xiàn)發(fā)送消息的操作界面,創(chuàng)建Socket實(shí)例,得到服務(wù)器的IP地址,更新控件,連接和斷開等,具體代碼如下:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
namespace 多人聊天程序Client端
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txtIP;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.RichTextBox txtSendMsg;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.RichTextBox txtRecvMsg;
private System.Windows.Forms.TextBox txtPort;
private System.Windows.Forms.Button button5;
private System.ComponentModel.Container components = null;
byte[] m_dataBuffer = new byte[10];
IAsyncResult result;
public AsyncCallback pfnCallBack ;
private System.Windows.Forms.Label status;
private System.Windows.Forms.Label label5;
public Socket clientSocket;
public Form1()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.txtIP = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.txtPort = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.txtSendMsg = new System.Windows.Forms.RichTextBox();
this.label4 = new System.Windows.Forms.Label();
this.status = new System.Windows.Forms.Label();
this.txtRecvMsg = new System.Windows.Forms.RichTextBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.label5 = new System.Windows.Forms.Label();
this.button5 = new System.Windows.Forms.Button();
this.SuspendLayout();
// label1
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(16, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(60, 17);
this.label1.TabIndex = 0;
this.label1.Text = "服務(wù)器IP:";
// txtIP
this.txtIP.Location = new System.Drawing.Point(80, 24);
this.txtIP.Name = "txtIP";
this.txtIP.Size = new System.Drawing.Size(160, 21);
this.txtIP.TabIndex = 1;
this.txtIP.Text = "";
// label2
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(16, 56);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(35, 17);
this.label2.TabIndex = 2;
this.label2.Text = "端口:";
// txtPort
this.txtPort.Location = new System.Drawing.Point(80, 56);
this.txtPort.Name = "txtPort";
this.txtPort.Size = new System.Drawing.Size(40, 21);
this.txtPort.TabIndex = 3;
this.txtPort.Text = "";
// label3
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(16, 96);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(110, 17);
this.label3.TabIndex = 4;
this.label3.Text = "發(fā)送信息給服務(wù)器:";
// txtSendMsg
this.txtSendMsg.Location = new System.Drawing.Point(16, 120);
this.txtSendMsg.Name = "txtSendMsg";
this.txtSendMsg.Size = new System.Drawing.Size(224, 88);
this.txtSendMsg.TabIndex = 5;
this.txtSendMsg.Text = "";
// label4
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(16, 248);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(60, 17);
this.label4.TabIndex = 6;
this.label4.Text = "連接狀態(tài):";
// status
this.status.Location = new System.Drawing.Point(80, 248);
this.status.Name = "status";
this.status.Size = new System.Drawing.Size(192, 23);
this.status.TabIndex = 7;
// txtRecvMsg
this.txtRecvMsg.Location = new System.Drawing.Point(264, 80);
this.txtRecvMsg.Name = "txtRecvMsg";
this.txtRecvMsg.ReadOnly = true;
this.txtRecvMsg.Size = new System.Drawing.Size(224, 144);
this.txtRecvMsg.TabIndex = 8;
this.txtRecvMsg.Text = "";
// button1
this.button1.Location = new System.Drawing.Point(280, 16);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(88, 32);
this.button1.TabIndex = 9;
this.button1.Text = "連接";
this.button1.Click += new System.EventHandler(this.button1_Click);
// button2
this.button2.Location = new System.Drawing.Point(384, 16);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(88, 32);
this.button2.TabIndex = 10;
this.button2.Text = "斷開";
this.button2.Click += new System.EventHandler(this.button2_Click);
// button3
this.button3.Location = new System.Drawing.Point(280, 232);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(88, 32);
this.button3.TabIndex = 11;
this.button3.Text = "清空信息";
this.button3.Click += new System.EventHandler(this.button3_Click);
// button4
this.button4.Location = new System.Drawing.Point(384, 232);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(88, 32);
this.button4.TabIndex = 12;
this.button4.Text = "關(guān)閉";
this.button4.Click += new System.EventHandler(this.button4_Click);
// label5
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(264, 64);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(134, 17);
this.label5.TabIndex = 13;
this.label5.Text = "收到服務(wù)器發(fā)來的信息:";
// button5
this.button5.Location = new System.Drawing.Point(16, 208);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(224, 32);
this.button5.TabIndex = 14;
this.button5.Text = "發(fā)送信息";
this.button5.Click += new System.EventHandler(this.button5_Click);
// Form1
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(512, 277);
this.Controls.Add(this.button5);
this.Controls.Add(this.label5);
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.txtRecvMsg);
this.Controls.Add(this.status);
this.Controls.Add(this.label4);
this.Controls.Add(this.txtSendMsg);
this.Controls.Add(this.label3);
this.Controls.Add(this.txtPort);
this.Controls.Add(this.label2);
this.Controls.Add(this.txtIP);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "多人聊天程序Client端";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
// 連接按鈕
private void button1_Click(object sender, System.EventArgs e)
{
// IP地址和端口號(hào)不能為空
if(txtIP.Text == "" || txtPort.Text == "")
{
MessageBox.Show("請(qǐng)先完整填寫服務(wù)器IP地址和端口號(hào)!", "提示");
return;
}
try
{
// 創(chuàng)建Socket實(shí)例
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 得到服務(wù)器的IP地址
IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
Int32 port = Int32.Parse(txtPort.Text);
// 創(chuàng)建遠(yuǎn)程終結(jié)點(diǎn)
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// 連接到遠(yuǎn)程服務(wù)器
clientSocket.Connect(remoteEP);
if(clientSocket.Connected)
{
UpdateControls(true);
WaitForData(); // 異步等待數(shù)據(jù)
}
}
catch(SocketException se)
{
MessageBox.Show (se.Message, "提示");
UpdateControls(false);
}
}
// 等待數(shù)據(jù)
public void WaitForData()
{
try
{
if(pfnCallBack == null)
{
// 當(dāng)連接上的客戶有寫的操作的時(shí)候,調(diào)用回調(diào)函數(shù)
pfnCallBack = new AsyncCallback(OnDataReceived);
}
SocketPacket socketPacket = new SocketPacket();
socketPacket.thisSocket = clientSocket;
result = clientSocket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
SocketFlags.None, pfnCallBack, socketPacket);
}
catch(SocketException se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 該類保存Socket以及發(fā)送給服務(wù)器的數(shù)據(jù)
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[1024]; // 發(fā)給服務(wù)器的數(shù)據(jù)
}
// 接收數(shù)據(jù)
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState ;
// EndReceive完成BeginReceive異步調(diào)用,返回服務(wù)器寫入流的字節(jié)數(shù)
int iRx = theSockId.thisSocket.EndReceive(asyn);
// 加 1 是因?yàn)樽址?'\0' 作為結(jié)束標(biāo)志符
char[] chars = new char[iRx + 1];
// 用UTF8格式來將string信息轉(zhuǎn)化成byte數(shù)組形式
System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
int charLen = decoder.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
// 將收到的信息顯示在信息列表中
txtRecvMsg.Text = txtRecvMsg.Text + szData;
// 等待數(shù)據(jù)
WaitForData();
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket已經(jīng)關(guān)閉!\n");
}
catch(SocketException se)
{
if(se.ErrorCode == 10054)
{
string msg = "服務(wù)器" + "停止服務(wù)!" + "\n";
txtRecvMsg.Text = txtRecvMsg.Text + msg;
clientSocket.Close();
clientSocket = null;
UpdateControls(false);
}
else
{
MessageBox.Show(se.Message, "提示");
}
}
}
// 更新控件。連接和斷開(發(fā)送信息)按鈕的狀態(tài)是互斥的
private void UpdateControls(bool connected)
{
button1.Enabled = !connected;
button2.Enabled = connected;
button5.Enabled = connected;
if(connected)
{
status.Text = "已連接";
}
else
{
status.Text = "無連接";
}
}
// 斷開按鈕
private void button2_Click(object sender, System.EventArgs e)
{
// 關(guān)閉Socket
if(clientSocket != null)
{
clientSocket.Close();
clientSocket = null;
UpdateControls(false);
}
}
// 發(fā)送信息按鈕
private void button5_Click(object sender, System.EventArgs e)
{
try
{
// 如果客戶與服務(wù)器有連接,則允許發(fā)送信息
if(clientSocket.Connected)
{
string msg = txtSendMsg.Text + "\n";
// 用UTF8格式來將string信息轉(zhuǎn)化成byte數(shù)組形式
byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg);
if(clientSocket != null)
{
// 發(fā)送數(shù)據(jù)
clientSocket.Send(byData);
}
}
}
catch(Exception se)
{
MessageBox.Show(se.Message, "提示");
}
}
// 清空按鈕
private void button3_Click(object sender, System.EventArgs e)
{
txtRecvMsg.Clear(); // 清空信息列表
}
// 關(guān)閉按鈕
private void button4_Click(object sender, System.EventArgs e)
{
// 關(guān)閉Socket
if(clientSocket != null)
{
clientSocket.Close();
clientSocket = null;
}
Close(); // 關(guān)閉窗體
}
private void Form1_Load(object sender, System.EventArgs e)
{
UpdateControls(false); // 初始化時(shí),只有連接按鈕可用
}
}
}
- C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能
- ASP.net(C#)實(shí)現(xiàn)簡(jiǎn)易聊天室功能
- C#簡(jiǎn)單聊天室雛形
- C#使用WebSocket實(shí)現(xiàn)聊天室功能
- C#實(shí)現(xiàn)簡(jiǎn)易多人聊天室
- C#使用Socket實(shí)現(xiàn)本地多人聊天室
- c#基于WinForm的Socket實(shí)現(xiàn)簡(jiǎn)單的聊天室 IM
- C#制作簡(jiǎn)單的多人在線即時(shí)交流聊天室
- 分享一個(gè)C#編寫簡(jiǎn)單的聊天程序(詳細(xì)介紹)
- C#基于Socket的TCP通信實(shí)現(xiàn)聊天室案例
相關(guān)文章
C#實(shí)現(xiàn)Word轉(zhuǎn)為PDF的方法
今天小編就為大家分享一篇關(guān)于C#實(shí)現(xiàn)Word轉(zhuǎn)為PDF的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01
WPF利用ValueConverter實(shí)現(xiàn)值轉(zhuǎn)換器
值轉(zhuǎn)換器在WPF開發(fā)中是非常常見的,值轉(zhuǎn)換器可以幫助我們很輕松地實(shí)現(xiàn),界面數(shù)據(jù)展示的問題。本文將通過WPF?ValueConverter實(shí)現(xiàn)簡(jiǎn)單的值轉(zhuǎn)換器,希望對(duì)大家有所幫助2023-03-03
C#實(shí)現(xiàn)將PPT轉(zhuǎn)換成HTML的方法
這篇文章主要介紹了C#實(shí)現(xiàn)將PPT轉(zhuǎn)換成HTML的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
描述C#多線程中l(wèi)ock關(guān)鍵字的使用分析
本篇文章是對(duì)C#多線程中l(wèi)ock關(guān)鍵字的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
關(guān)于C#操作文件路徑(Directory)的常用靜態(tài)方法詳解
這篇文章主要給大家介紹了關(guān)于C#操作文件路徑(Directory)的常用靜態(tài)方法,Directory類位于System.IO 命名空間,Directory類提供了在目錄和子目錄中進(jìn)行創(chuàng)建移動(dòng)和列舉操作的靜態(tài)方法,需要的朋友可以參考下2021-08-08

