




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、一、服務(wù)器/客戶端聊天室模型1.首先啟動聊天室服務(wù)器,使得TcpListener開始監(jiān)聽端口,此時TcpListener會進(jìn)入Pending狀態(tài),等待客戶端連接;2.其次,當(dāng)有客戶端連接后,通過AccepSocket返回與客戶端連接的Socket對象,然后通過讀寫Socket對象完成與聊天室客戶端的數(shù)據(jù)傳輸。聊天室客戶端成功啟動后,首先創(chuàng)建一個Socket對象,然后通過這個Socket對象連接聊天室服務(wù)器,連接成功后開通Socket完成數(shù)據(jù)的接收和發(fā)送處理。二、系統(tǒng)功能設(shè)計本設(shè)計為一個簡單的聊天室工具,設(shè)計基本的聊天功能,如聊天、列表維護(hù)等。系統(tǒng)主要為兩大塊:聊天室服務(wù)器及聊天室客戶端。服務(wù)器
2、界面設(shè)計如下:客戶端界面設(shè)計如下:三、聊天協(xié)議的應(yīng)答A網(wǎng)絡(luò)B主機與主機通信主要識別身份(標(biāo)識設(shè)備用IP)及通信協(xié)議網(wǎng)絡(luò)應(yīng)用程序端口號接收數(shù)據(jù)注:1.IP地址是總機,端口號是分機(傳輸層)2.端口號為16位二進(jìn)制數(shù),范圍0到65535,但實際編程只能用1024以上端口號Socket編程首先,我們了解常用網(wǎng)絡(luò)編程協(xié)議。我們用得最多的協(xié)議是UDP和TCP,UDP是不可靠傳輸服務(wù),TCP是可靠傳輸服務(wù)。UDP就像點對點的數(shù)據(jù)傳輸一樣,發(fā)送者把數(shù)據(jù)打包,包上有收信者的地址和其他必要信息,至于收信者能不能收到,UDP協(xié)議并不保證。而TCP協(xié)議就像(實際他們是一個層次的網(wǎng)絡(luò)協(xié)議)是建立在UDP的基礎(chǔ)上,加入
3、了校驗和重傳等復(fù)雜的機制來保證數(shù)據(jù)可靠的傳達(dá)到收信者。一個是面向連接一個無連接,各有用處,在一些數(shù)據(jù)傳輸率高的場合如視頻會議傾向于UDP,而對一些數(shù)據(jù)安全要求高的地方如下載文件就傾向于TCP。Socket網(wǎng)絡(luò)應(yīng)用程序電話機訪問通信協(xié)議聊天協(xié)議的應(yīng)答:聊天狀態(tài):CLOSED和CONNECTED狀態(tài)執(zhí)行CONN命令后進(jìn)入CONNECTED狀態(tài),執(zhí)行下列命令:CONN:連接聊天室服務(wù)器JOIN:加入聊天(通知其他用戶本人已經(jīng)加入聊天室服務(wù)器)LIST:列出所有的用戶(向客戶端發(fā)送全部的登錄用戶名字)CHAT:發(fā)送聊天信息(公開的聊天信息)PRIV:進(jìn)行私聊(三個參數(shù):私聊信息用戶;接收私聊信息用戶;
4、發(fā)送信息)EXIT:客戶端向服務(wù)器發(fā)送離開請求;QUIT:退出聊天,服務(wù)器向客戶端發(fā)送退出命令(執(zhí)行QUIT命令聊天狀態(tài)變?yōu)镃LOSED)四、系統(tǒng)實現(xiàn)服務(wù)器協(xié)議解析:當(dāng)有客戶端連接聊天室服務(wù)器后,服務(wù)器立刻為這個客戶建立一個數(shù)據(jù)接收的線程(多用戶程序必備)。在接收線程中,如果收到聊天命令,就對其進(jìn)行解析處理,服務(wù)器可以處理五種命令:CONNLISTCHATPRIVEXIT。服務(wù)器接收到CONN命令,就向其他用戶發(fā)送JOIN命令告訴有用戶加入,然后把當(dāng)前的全部用戶信息返回給剛剛加入的用戶,以便在界面上顯示用戶列表。當(dāng)接收到EXIT命令后,就清除當(dāng)前用戶的信息,然后向其他用戶發(fā)送QUIT命令,告訴
5、其他用戶退出了,這些用戶的客戶端把離開的用戶從用戶列表中刪除。聊天室客戶端的協(xié)議解析:當(dāng)客戶端連接到服務(wù)器后,服務(wù)器立刻建立一個數(shù)據(jù)接收的獨立線程。在接收線程中,如果收到了聊天命令,就對其進(jìn)行解析處理。聊天室客戶端一共處理的命令有五種:OKERRLISTJOINQUIT命令。五、程序設(shè)計(代碼)服務(wù)器端設(shè)計:引入網(wǎng)絡(luò)操作命名空間System.Net、System.Net.Sockets;線程處理命名空間System.Threading第一步:界面設(shè)計及類與相關(guān)成員的定義對界面進(jìn)行設(shè)計(簡單)對內(nèi)部函數(shù)進(jìn)行設(shè)計(要編寫一個獨立的類即Client類,封裝了客戶端的信息與連接,每一個客戶進(jìn)入聊天室,
6、就創(chuàng)建一個Client對象,用于保存該用戶的信息并接收用戶數(shù)據(jù)和發(fā)送信息到客戶端)幾個重要的類:TcpListener類(服務(wù)器套接字創(chuàng)建)、Socket類internal static Hashtable clients = new Hashtable();/clients數(shù)組保存當(dāng)前在線用戶的client對象 private TcpListener listener;/該服務(wù)器默認(rèn)的監(jiān)聽端口號 static int MAX_NUM = 100; /服務(wù)器可以支持的客戶端的最大連接數(shù) internal static bool SocketServiceFlag = false;/開始服務(wù)的標(biāo)
7、志/獲得本地局域網(wǎng)或者撥號動態(tài)分配的IP地址,在啟動服務(wù)器時會用到IP地址 private string getIPAddress() /獲得本機局域網(wǎng)IP地址 IPAddress Addresslist=Dns.GetHostEntry(Dns.GetHostName().AddressList; if (Addresslist.Length1) return ; return Addresslist0.ToString(); /獲得動態(tài)的IP地址 private static string getDynamicIPAddress() IPAddress Addresslist = Dns.
8、GetHostEntry(Dns.GetHostName().AddressList; if (Addresslist.Length 2) return ; return Addresslist1.ToString(); /服務(wù)器監(jiān)聽的端口號通過getValidPort()函數(shù)獲得 private int getValidPort(string port) int lport; /測試端口號是否有效 try /是否為空 if (port = ) throw new ArgumentException(端口號為空,不能啟動服務(wù)器); lport = System.Convert.ToInt32(
9、port); catch (Exception e) Console.WriteLine(無效的端口號: + e.ToString(); this.rtbSocketMsg.AppendText(無效的端口號: + e.ToString() + n); return -1; return lport; private void btnSocketStart_Click(object sender, EventArgs e) int port = getValidPort(tbSocketPort.Text); if (port = MAX_NUM) this.rtbSocketMsg.Appe
10、ndText(已經(jīng)達(dá)到了最大連接數(shù): + MAX_NUM + ,拒絕新的鏈接n); socket.Close(); else /啟動一個新的線程 /執(zhí)行方法this.ServiceClient,處理用戶相應(yīng)的請求 ChatSever.Client.Client client = new ChatSever.Client.Client(this, socket); Thread clientService = new Thread(new ThreadStart(client.ServiceClient); clientService.Start(); Thread.Sleep(200);/提高
11、性能整體速度,原因不詳 catch (Exception ex) this.rtbSocketMsg.AppendText(ex.Message.ToString() + n); private void tbSocketPort_TextChanged(object sender, EventArgs e) if (this.tbSocketPort.Text!=) this.btnSocketStart.Enabled = true; /下面為一些界面處理函數(shù) private void btnSocketStop_Click(object sender, EventArgs e) Form
12、1.SocketServiceFlag = false; this.btnSocketStart.Enabled = true; this.btnSocketStop.Enabled = false; public void addUser(string username) this.rtbSocketMsg.AppendText(username + 已經(jīng)加入n);/將剛連接的用戶名加入到當(dāng)前在線用戶列表中 this.lbSocketClients.Items.Add(username); this.tbSocketClientsNum.Text = System.Convert.ToStr
13、ing(clients.Count); public void removeUser(string username) this.rtbSocketMsg.AppendText(username + 已經(jīng)離開n);/將剛連接的用戶名加入到當(dāng)前在線用戶列表中 this.lbSocketClients.Items.Remove(username); this.tbSocketClientsNum.Text = System.Convert.ToString(clients.Count); public string GetUserList() string Rtn = ; for (int i =
14、 0; i lbSocketClients.Items.Count; i+) Rtn += lbSocketClients.Itemsi.ToString() + |; return Rtn; public void updateUI(string msg) this.rtbSocketMsg.AppendText(msg + n); private void Form1_FormClosing(object sender, FormClosingEventArgs e) Form1.SocketServiceFlag = false; /下面為Client類定義public class Cl
15、ient private string name;/保存用戶名 private Socket currentSocket = null;/保存與當(dāng)前用戶連接的Socket對象 private string ipAddress;/保存用戶的IP地址 private Form1 server; /保存當(dāng)前連接狀態(tài) /Closed-connected-closed private string state = closed; public Client(Form1 server, Socket clientSocket) this.server = server; this.currentSocke
16、t = clientSocket; ipAddress = getRemoteIPAddress(); public string Name get return name; set name = value; public Socket CurrentSocket get return currentSocket;/ipAddress private string getRemoteIPAddress() return (IPEndPoint)currentSocket.RemoteEndPoint).Address.ToString(); /SendToClient()方法實現(xiàn)了向客戶端發(fā)
17、送命令請求的功能 private void SendToClient(Client client, string msg) System.Byte message = System.Text.Encoding.Default.GetBytes(msg.ToCharArray(); client.currentSocket.Send(message, message.Length, 0); /ServiceClient 方法用于和客戶端進(jìn)行數(shù)據(jù)通信,包括接收客戶端的請求 /它根據(jù)不同的請求命令執(zhí)行相應(yīng)的操作,并將處理結(jié)果返回到客戶端 /ServiceClient()函數(shù)為服務(wù)器接收客戶數(shù)據(jù)的線程
18、主體,主要用來接收用戶發(fā)送來的數(shù)據(jù),并處理聊天命令 public void ServiceClient() string tokens=null; byte buff=new byte1024; bool keepConnect=true; /用循環(huán)來不斷地與客戶端進(jìn)行交互,直到客戶端發(fā)出“EXIT”命令 /將keepConnect職為false,退出循環(huán),關(guān)閉連接,并中止當(dāng)前線程 while(keepConnect&Form1.SocketServiceFlag) /tokens=null; try if(currentSocket=null|currentSocket.Available+
19、receiver+”:”+content; /僅將信息轉(zhuǎn)發(fā)給法送者和接收者 if (Form1.clients.Contains(sender) SendToClient(Client)Form1.clientssender,message); if (Form1.clients.Contains(receiver) SendToClient(Client)Form1.clientsreceiver,message); server.updateUI(tokens1); else /send err to server SendToClient(this,ERR|state error,ple
20、ase login first); else if (tokens0=EXIT) /此時收到的命令的格式為:命令標(biāo)識符EXIT|發(fā)送者的用戶名:發(fā)送內(nèi)容| /向所有當(dāng)前在線的用戶發(fā)送該用戶已離開的消息 if(Form1.clients.Contains(tokens1) Client client=(Client)Form1.clients(tokens1); /將該用戶對應(yīng)Client對象從clients中刪除 Hashtable syncClients=Hashtable.Synchronized(Form1.clients); syncClients.Remove(
21、); server.removeUser(); /向客戶端發(fā)送QUIT命令 string message =QUIT|+tokens1; System.Collections.IEnumerator myEnumerator=Form1.clients.Values.GetEnumerator(); while(myEnumerator.MoveNext() Client c =(Client)myEnumerator.Current; /將發(fā)送者的用戶名:發(fā)送內(nèi)容 轉(zhuǎn)發(fā)給用戶 SendToClient(c,message); server.updateUI(QUIT);
22、 /退出當(dāng)前線程 break; Thread.Sleep(200); 客戶端設(shè)計:包含一個類ChatClientForm,該類封裝了聊天室客戶端界面和聊天命令處理邏輯。其中一個重要的類TcpClient類(用于與服務(wù)器的連接)TcpClient tcpClient; /與服務(wù)器的鏈接 private NetworkStream Stream;/與服務(wù)器數(shù)據(jù)交互的流通道 private static string CLOSED = closed; private static string CONNECTED = connected; private string state = CLOSED;
23、 private bool stopFlag; private Color color;/保存當(dāng)前客戶端顯示的顏色 /連接聊天室服務(wù)器/通過TcpClient方法連接聊天室服務(wù)器并發(fā)送CONN消息命令 private void btnLogin_Click_1(object sender, EventArgs e) if (state = CONNECTED) return; if (this.tbUserName.TextLength = 0) MessageBox.Show(請輸入您的昵稱!, 提示信息, MessageBoxButtons.OK, MessageBoxIcon.Excla
24、mation); this.tbUserName.Focus();/為控件設(shè)置焦點,人性化設(shè)計 return; try /創(chuàng)建一個客戶端套接字,它是Login的一個公共屬性 tcpClient = new TcpClient();/將被傳遞給ChatClient窗體 tcpClient.Connect(IPAddress.Parse(txtHost.Text), Int32.Parse(txtPort.Text);/向指定的IP地址服務(wù)器發(fā)出連接請求 Stream = tcpClient.GetStream(); /獲得與服務(wù)器數(shù)據(jù)交互的流通道 NetworksStream /啟動一個新的線程
25、,執(zhí)行方法this.ServerResponse(),以便來響應(yīng)從服務(wù)器發(fā)回的信息 Thread thread1 = new Thread(new ThreadStart(this.ServerResponse); thread1.Start(); /向服務(wù)器發(fā)送CONN請求命令 /此命令的格式與服務(wù)器端的定義的格式一致 /命令格式為:命令標(biāo)志符CONN|發(fā)送者的用戶名 string cmd = CONN| + this.tbUserName.Text + |; /將字符串轉(zhuǎn)化為字符數(shù)組 Byte outbytes = System.Text.Encoding.Default.GetBytes
26、(cmd.ToCharArray(); Stream.Write(outbytes, 0, outbytes.Length); catch (Exception ex) MessageBox.Show(ex.Message); private void btnSend_Click_1(object sender, EventArgs e) try if (!this.cbPrivate.Checked) /此時命令的格式是:命令標(biāo)識符CHAT|發(fā)送者的用戶名:發(fā)送內(nèi)容| string message = CHAT| + this.tbUserName.Text + : + tbSendContent.Text; tbSendContent.Text = ; tbSendContent.Focus(); byte outbytes = System.Text.Encoding.Default.GetBytes(message.ToCharArray(); /將字符串轉(zhuǎn)化為字符數(shù)組 Stream.Write(outbytes, 0, outbytes.Length); else if (lstUser
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度文化娛樂產(chǎn)業(yè)股權(quán)轉(zhuǎn)讓及代持合作協(xié)議
- 2025年教師實習(xí)合同協(xié)議樣本:數(shù)學(xué)與科學(xué)教育教師實習(xí)協(xié)議
- 2025遼寧大連長興控股集團有限公司及所屬公司招聘9人筆試參考題庫附帶答案詳解
- 教學(xué)技術(shù)與藝術(shù)知到智慧樹章節(jié)測試課后答案2024年秋西南大學(xué)
- 健美操知到智慧樹章節(jié)測試課后答案2024年秋武漢學(xué)院
- 2025寧夏中匯化工有限公司招聘8人筆試參考題庫附帶答案詳解
- 2025中國建材集團有限公司招聘14人筆試參考題庫附帶答案詳解
- 2024遼寧盤錦市政建設(shè)集團社會招聘31人查看職位筆試參考題庫附帶答案詳解
- 2025年上半年六盤水六枝特區(qū)事業(yè)單位及招考易考易錯模擬試題(共500題)試卷后附參考答案
- 2025年上半年保山市消防救援支隊防火監(jiān)督科招聘消防文員4名易考易錯模擬試題(共500題)試卷后附參考答案
- 售后服務(wù)流程圖
- 建筑地基處理技術(shù)規(guī)范JGJ79-2012
- 印象主義、后印象主義課件
- 《中華傳統(tǒng)文化》第1課-炎黃始-華夏悠遠(yuǎn)教學(xué)課件
- 日常監(jiān)督檢查表
- 隊列訓(xùn)練教程ppt課件(PPT 86頁)
- 第三章-農(nóng)村公共管理組織課件
- 注塑員工培訓(xùn)
- JMP操作簡要培訓(xùn)
- 勝利油田壓驅(qū)技術(shù)工藝研究進(jìn)展及下步工作方向
- 研究生復(fù)試匯報ppt
評論
0/150
提交評論