C#下如何实现服务器 + 客户端的聊天程序
最近也在接觸SOCKET編程,在當今這樣一個網絡時代,很多技術都以網絡為中心在誕生,至少我認為是這樣的,而SOCKET套接字接口,在實現網絡通訊上處于關鍵地位,所以不會SOCKET是不行的。
首先,本文主要是針對那些剛接觸SOCKET編程的朋友,如果是高手,就可以不看此文啦,可以去陪陪老婆,比如逛街或看電視...
在開始之前,我們需要預習一些基礎知識:
什么是SOCKET套接字?
SOCKET通常有那幾種數據格式?
線程的概念?
(以上基本知識我就不講了,網上這方面資料很多的,大家找資料看下吧)
我要介紹的是一個服務器端+客戶端的聊天系統,程序比較簡單,我先把程序運行的界面給大家看下:
上面是服務器端運行界面;下面把客戶端界面貼給大家看下:
功能比較簡單,服務器的端口號可以在“系統菜單”里面的參數配置進行修改的。
看了上面的圖,下面我們就給大家把代碼貼出來:(因為程序比較簡單,所以本人就沒有去分層啦)
服務器端代碼:
2?usingSystem.Collections.Generic;
3?usingSystem.ComponentModel;
4?usingSystem.Data;
5?usingSystem.Drawing;
6?usingSystem.Text;
7?usingSystem.Windows.Forms;
8?
9?usingSystem.Net;
10?usingSystem.Net.Sockets;
11?usingSystem.Threading;
12?usingSystem.Xml;
13?
14?namespaceServer
15?{
16?publicpartial?classServerMain?:?Form
17?{
18?publicServerMain()
19?{
20?InitializeComponent();
21?}
22?
23?privatevoidServerMain_Load(objectsender,?EventArgs?e)
24?{
25?this.CmdStar.Enabled?=true;
26?this.CmdStop.Enabled?=false;
27?}
28?
29?privatevoid配置參數ToolStripMenuItem_Click(objectsender,?EventArgs?e)
30?{
31?Set?TSet?=newSet();
32?TSet.ShowDialog();
33?}
34?
35?privatevoid關于ToolStripMenuItem_Click(objectsender,?EventArgs?e)
36?{
37?About?TAbout?=newAbout();
38?TAbout.Show();
39?}
40?///<summary>
41?///獲得XML文件中的端口號
42?///</summary>
43?///<returns></returns>
44?privateintGetPort()
45?{
46?try
47?{
48?XmlDocument?TDoc?=newXmlDocument();
49?TDoc.Load("Settings.xml");
50?stringTPort?=TDoc.GetElementsByTagName("ServerPort")[0].InnerXml;
51?returnConvert.ToInt32(TPort);
52?
53?}
54?catch{?return6600;?}//默認是6600
55?}
56?
57?//聲明將要用到的類
58?privateIPEndPoint?ServerInfo;//存放服務器的IP和端口信息
59?privateSocket?ServerSocket;//服務端運行的SOCKET
60?privateThread?ServerThread;//服務端運行的線程
61?privateSocket[]?ClientSocket;//為客戶端建立的SOCKET連接
62?privateintClientNumb;//存放客戶端數量
63?privatebyte[]?MsgBuffer;//存放消息數據
64?
65?privatevoidCmdStar_Click(objectsender,?EventArgs?e)
66?{
67?ServerSocket?=newSocket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);
68?ServerInfo=newIPEndPoint(IPAddress.Any,this.GetPort());
69?ServerSocket.Bind(ServerInfo);//將SOCKET接口和IP端口綁定
70?ServerSocket.Listen(10);//開始監聽,并且掛起數為10
71?
72?ClientSocket?=newSocket[65535];//為客戶端提供連接個數
73?MsgBuffer?=newbyte[65535];//消息數據大小
74?ClientNumb?=0;//數量從0開始統計
75?
76?ServerThread?=newThread(RecieveAccept);//將接受客戶端連接的方法委托給線程
77?ServerThread.Start();//線程開始運行
78?
79?CheckForIllegalCrossThreadCalls?=false;//不捕獲對錯誤線程的調用
80?
81?this.CmdStar.Enabled?=false;
82?this.CmdStop.Enabled?=true;
83?this.StateMsg.Text?="服務正在運行"+"運行端口:"+this.GetPort().ToString();
84?this.ClientList.Items.Add("服務于?"+DateTime.Now.ToString()?+"開始運行.");
85?}
86?
87?//接受客戶端連接的方法
88?privatevoidRecieveAccept()
89?{
90?while(true)
91?{
92?ClientSocket[ClientNumb]?=ServerSocket.Accept();
93?ClientSocket[ClientNumb].BeginReceive(MsgBuffer,?0,?MsgBuffer.Length,?0,?newAsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]);
94?this.ClientList.Items.Add(ClientSocket[ClientNumb].RemoteEndPoint.ToString()+"成功連接服務器.");
95?ClientNumb++;
96?}
97?}
98?
99?//回發數據給客戶端
100?privatevoidRecieveCallBack(IAsyncResult?AR)
101?{
102?try
103?{
104?Socket?RSocket?=(Socket)AR.AsyncState;
105?intREnd?=RSocket.EndReceive(AR);
106?for(inti?=0;?i?<ClientNumb;?i++)
107?{
108?if(ClientSocket[i].Connected)
109?{
110?ClientSocket[i].Send(MsgBuffer,?0,?REnd,0);
111?}
112?RSocket.BeginReceive(MsgBuffer,?0,?MsgBuffer.Length,?0,?newAsyncCallback(RecieveCallBack),?RSocket);
113?
114?}
115?}
116?catch{?}
117?
118?}
119?
120?privatevoidCmdStop_Click(objectsender,?EventArgs?e)
121?{
122?ServerThread.Abort();//線程終止
123?ServerSocket.Close();//關閉SOCKET
124?
125?this.CmdStar.Enabled?=true;
126?this.CmdStop.Enabled?=false;
127?this.StateMsg.Text?="等待運行";
128?this.ClientList.Items.Add("服務于?"+DateTime.Now.ToString()?+"停止運行.");
129?}
130?
131?
132?
133?}
134?}
客戶端代碼:
2?usingSystem.Collections.Generic;
3?usingSystem.ComponentModel;
4?usingSystem.Data;
5?usingSystem.Drawing;
6?usingSystem.Text;
7?usingSystem.Windows.Forms;
8?
9?usingSystem.Net;
10?usingSystem.Net.Sockets;
11?
12?namespaceClient
13?{
14?publicpartial?classClientMain?:?Form
15?{
16?publicClientMain()
17?{
18?InitializeComponent();
19?}
20?
21?privateIPEndPoint?ServerInfo;
22?privateSocket?ClientSocket;
23?privateByte[]?MsgBuffer;
24?privateByte[]?MsgSend;
25?
26?privatevoidClientMain_Load(objectsender,?EventArgs?e)
27?{
28?this.CmdSend.Enabled?=false;
29?this.CmdExit.Enabled?=false;
30?
31?ClientSocket?=newSocket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);
32?MsgBuffer?=newByte[65535];
33?MsgSend?=newByte[65535];
34?CheckForIllegalCrossThreadCalls?=false;
35?
36?Random?TRand=newRandom();
37?this.UserName.Text?="用戶"+TRand.Next(10000).ToString();
38?}
39?
40?privatevoidCmdEnter_Click(objectsender,?EventArgs?e)
41?{
42?ServerInfo?=newIPEndPoint(IPAddress.Parse(this.ServerIP.Text),?Convert.ToInt32(this.ServerPort.Text));
43?
44?try
45?{
46?ClientSocket.Connect(ServerInfo);
47?
48?ClientSocket.Send(Encoding.Unicode.GetBytes("用戶:?"+this.UserName.Text?+"進入系統!\n"));
49?
50?ClientSocket.BeginReceive(MsgBuffer,?0,?MsgBuffer.Length,?0,?newAsyncCallback(ReceiveCallBack),?null);
51?
52?this.SysMsg.Text?+="登錄服務器成功!\n";
53?this.CmdSend.Enabled?=true;
54?this.CmdEnter.Enabled?=false;
55?this.CmdExit.Enabled?=true;
56?}
57?catch
58?{
59?MessageBox.Show("登錄服務器失敗,請確認服務器是否正常工作!");
60?}
61?}
62?
63?privatevoidReceiveCallBack(IAsyncResult?AR)
64?{
65?try
66?{
67?intREnd?=ClientSocket.EndReceive(AR);
68?this.RecieveMsg.AppendText(Encoding.Unicode.GetString(MsgBuffer,?0,?REnd));
69?ClientSocket.BeginReceive(MsgBuffer,?0,?MsgBuffer.Length,?0,?newAsyncCallback(ReceiveCallBack),?null);
70?
71?}
72?catch
73?{
74?MessageBox.Show("已經與服務器斷開連接!");
75?this.Close();
76?}
77?
78?}
79?
80?privatevoidCmdSend_Click(objectsender,?EventArgs?e)
81?{
82?MsgSend?=Encoding.Unicode.GetBytes(this.UserName.Text?+"說:\n"+this.SendMsg.Text?+"\n");
83?if(ClientSocket.Connected)
84?{
85?ClientSocket.Send(MsgSend);
86?this.SendMsg.Text?="";
87?}
88?else
89?{
90?MessageBox.Show("當前與服務器斷開連接,無法發送信息!");
91?}
92?}
93?
94?privatevoidCmdExit_Click(objectsender,?EventArgs?e)
95?{
96?if(ClientSocket.Connected)
97?{
98?ClientSocket.Send(Encoding.Unicode.GetBytes(this.UserName.Text?+"離開了房間!\n"));
99?ClientSocket.Shutdown(SocketShutdown.Both);
100?ClientSocket.Disconnect(false);
101?}
102?ClientSocket.Close();
103?
104?this.CmdSend.Enabled?=false;
105?this.CmdEnter.Enabled?=true;
106?this.CmdExit.Enabled?=false;
107?}
108?
109?privatevoidRecieveMsg_TextChanged(objectsender,?EventArgs?e)
110?{
111?this.RecieveMsg.ScrollToCaret();
112?}
113?
114?privatevoidSendMsg_KeyDown(objectsender,?KeyEventArgs?e)
115?{
116?if(e.Control?&&e.KeyValue?==13)
117?{
118?e.Handled?=true;
119?this.CmdSend_Click(this,?null);
120?}
121?}
122?
123?
124?
125?
126?}
127?}
我只對服務器端的代碼做了注釋,客戶端就沒有寫注釋了,因為代碼是差不多的。區別在于客戶端不需要監聽,也不需要啟用線程進行委托。
關于?ServerSocket?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);
這句代碼,我想給初學者解釋一下,這里“AddressFamily.InterNetwork”表示的是使用IPV4地址,“SocketType.Stream”表示使用的是流格式(另外還有數據包格式和原始套接字格式),“ProtocolType.Tcp”表示使用TCP協議(另外還有很多其它協議,例如大家常看到的UDP協議)。
另外關于SOCKET類中的BeginReceive方法,請大家參考MSDN,里面有詳細說明。
希望本人給的這個程序可以起到一個拋磚引玉的作用。
備注:
//今天有朋友加我QQ問我有關服務端“Settings.xml”文件的內容部分,我現在把內容貼出來,其實很簡單,就是方便服務端修改端口的。
<?xml?version="1.0"?encoding="utf-8"??>
<Server>
??<ServerPort>6600</ServerPort>
</Server>
完整的源碼我已經放在CSDN上面共享了,地址:http://download.csdn.net/user/lixyvip
轉載于:https://www.cnblogs.com/haiyabtx/archive/2012/07/31/2616246.html
總結
以上是生活随笔為你收集整理的C#下如何实现服务器 + 客户端的聊天程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简述 Java 垃圾回收机制
- 下一篇: c# char unsigned_dll