c#聊天室程序_第1頁
c#聊天室程序_第2頁
c#聊天室程序_第3頁
c#聊天室程序_第4頁
c#聊天室程序_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、精選優(yōu)質(zhì)文檔-傾情為你奉上精選優(yōu)質(zhì)文檔-傾情為你奉上專心-專注-專業(yè)專心-專注-專業(yè)精選優(yōu)質(zhì)文檔-傾情為你奉上專心-專注-專業(yè)計算機學(xué)院課程設(shè)計專 業(yè): 08網(wǎng)絡(luò)工程 課程名稱: TCP/IP協(xié)議分析實驗 課題名稱: 基于TCP協(xié)議的C#聊天程序 教 師: 桂學(xué)勤 學(xué) 號: 時 間: 2010 年 6月 18日目錄 TOC o 1-3 h z u 基于TCP協(xié)議的C#聊天程序前言隨著互聯(lián)網(wǎng)技術(shù)的飛速發(fā)展,基于網(wǎng)絡(luò)的即時通信技術(shù)也給人們帶來了諸多便利,人們也慢慢體會到了網(wǎng)上聊天的樂趣與無拘束的感覺。聊天工具作為當今使用最為廣泛的即時通信工具之一,可以方便的同網(wǎng)絡(luò)上的好友在線交流。在中國,最流行的

2、莫過于騰訊公司的QQ,伴隨著技術(shù)的不斷升級,騰訊公司也為我們帶來了越來越多的精彩的服務(wù)。這里我將利用Socket編程技術(shù)模擬QQ聊天功能,實現(xiàn)一個簡單的在線聊天室。一:需求分析1.1編寫目的編寫該軟件能夠?qū)ψ约核鶎W(xué)的東西進行一次系統(tǒng)的回顧,加深對TCP協(xié)議的理解以及提升自己實際開發(fā)的能力。1.2開發(fā)環(huán)境操作系統(tǒng):windows xp sp3內(nèi)存:2GCPU:AMD Athlon(tm) 64 X2 Dual Core Processor 5200+ 2.71GHz編程軟件:Microsoft Visual Studio 20101.3功能介紹該程序是利用c#語言編寫的一個基于Socket的簡單

3、聊天軟件,最要實現(xiàn)了用戶登錄,但登錄時只需要提供用戶名,不需要輸入密碼。具有私聊和群聊兩種聊天模式,即允許多人在線聊天,并且在線用戶聊天時,可以將消息發(fā)送給一個用戶,亦可以將消息發(fā)送給所有人。聊天的消息內(nèi)容包括:用戶名稱、發(fā)送時間、發(fā)送正文、以及消息模式。斷開連接的同時會關(guān)閉客戶端,此時用戶若希望聊天,需要再次登錄服務(wù)器。1.4Socket通信機制Socket編程是建立在應(yīng)用層TCP/IP協(xié)議之上的。目前最流行的是客戶機/服務(wù)器模式,在面向連接的 Client/Server 模型中,Server 端的 socket 總是等待一個 Client 端的請求??蛻魴C/服務(wù)器模型的工作流程圖如下圖所示

4、:服務(wù)器程序特點:一般啟動后就一直處于運行狀態(tài),以等待客戶機進程的請求;使用的端口往往是熟知端口,便于客戶機進程連接請求;一般擁有較多的系統(tǒng)資源,以便及時響應(yīng)各個客戶機進程的請求;可以并行處理多個客戶機進程的請求,但數(shù)目是有一定的限制;在通信時一般處于被動的一方,不需要知道客戶機的IP地址和端口信息。客戶機程序的特點: 在需要服務(wù)器進程的服務(wù)時將向服務(wù)器進程請求服務(wù),并建立通信連接,得到滿足并完成處理后就終止通信連接; 使用向系統(tǒng)申請的臨時端口與服務(wù)器進程進行通信,通信完成后將釋放該端口; 擁有相對較少的系統(tǒng)資源; 在通信時屬于主動的一方,需要事先知道服務(wù)器的IP地址和端口信息客戶機與服務(wù)器模

5、式又分為兩大類:面向連接的交互(TCP)和面向無連接的交互(UDP),本程序是面向連接的交互,交互機制如下圖:二:代碼實現(xiàn)2.1服務(wù)器端主要代碼負責監(jiān)聽客戶端請求,并根據(jù)客戶端命令執(zhí)行不同操作的Listener類,Listener.csusing System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Sockets;using System.Net;using System.Threading;using System.Collections.Specialize

6、d;using System.Runtime.Serialization;using System.IO;using System.Runtime.Serialization.Formatters.Binary;namespace TalkerServer class Listener public delegate void ShowMsg(ListenWindow lisWin, string svrInfo);/svrInfo要顯示的服務(wù)器信息,lisWin顯示的窗口對象 private ListenWindow lisWin = null;/服務(wù)器監(jiān)聽窗口對象 private Show

7、Msg smsg = null;/消息顯示委托對象 private int listenPort = 8888;/監(jiān)聽端口,默認8888 private const int maxPacket = 64 * 1024;/緩沖區(qū)大小 private Dictionary userMap = new Dictionary();/所有登陸服務(wù)器的用戶map private TcpListener tcpListener = null;/偵聽器 public int ListenPort get return this.listenPort; set this.listenPort = value;

8、public TcpListener TcpListener get return this.tcpListener; set this.tcpListener = value; public Dictionary UserMap get return this.userMap; set this.userMap = value; public void Listen(ShowMsg smsg,string svrInfo,ListenWindow lisWin) this.lisWin = lisWin; this.smsg = smsg; string connInfo = string.

9、Empty; IPAddress ipAddr = Dns.GetHostAddresses(Dns.GetHostName()0; tcpListener = new TcpListener(ipAddr,listenPort); tcpListener.Start(); connInfo += 服務(wù)器已經(jīng)啟動,正在監(jiān)聽客戶端的連接rn; smsg(lisWin, connInfo); while (true) byte packetBuff = new bytemaxPacket; Socket client = tcpListener.AcceptSocket(); client.Rec

10、eive(packetBuff); string userName = Encoding.Unicode.GetString(packetBuff).TrimEnd(0); if (userMap.ContainsKey(userName) & userMap.Count != 0) client.Send(Encoding.Unicode.GetBytes(0);/該用戶存在 else client.Send(Encoding.Unicode.GetBytes(1);/該用戶不存在 userMap.Add(userName,client);/保存客戶端到Map中 string svrlog

11、= string.Format(系統(tǒng)消息新用戶【0】在【1】已連接. 當前在線人數(shù):【2】rnrn, userName, DateTime.Now, userMap.Count); smsg(lisWin, svrlog);/利用委托更新服務(wù)器顯示日志 Thread clientThread = new Thread(new ParameterizedThreadStart(ThreadFunc);/開啟一個子線程執(zhí)行程序 clientThread.Start(userName); foreach(KeyValuePair user in userMap) string uName = use

12、r.Key as string; Socket clientSkt = user.Value as Socket; if (!uName.Equals(userName) clientSkt.Send(Encoding.Unicode.GetBytes(svrlog); /序列化在線用戶列表 private byte SerializeOnlineUserList(Object obj) StringCollection onlineUserList = new StringCollection(); foreach (object o in userMap.Keys) if (o != ob

13、j)/序列化的在線列表中不包含自身登陸用戶 onlineUserList.Add(o as string);/轉(zhuǎn)換語句 IFormatter format = new BinaryFormatter();/以二進制格式將對象或整個連接對 MemoryStream stream = new MemoryStream(); format.Serialize(stream, onlineUserList);/保持到內(nèi)存流 byte ret = stream.ToArray(); stream.Close(); return ret; public void ThreadFunc(Object obj

14、) Socket client = null; string userName = (string)obj; if (userMap.TryGetValue(userName, out client) if (client != null) while (true) try byte _cmdBuff = new byte128; client.Receive(_cmdBuff);/第一次接收命令,第二次接收內(nèi)容 string _cmd = string.Concat(_cmdBuff0.ToString(), _cmdBuff1.ToString(); /00對所有人,01請求用戶列表,02

15、斷開連接 if (_cmd = 00) byte _msgBuff = new bytemaxPacket; client.Receive(_msgBuff); foreach (KeyValuePair user in userMap) string uName = user.Key as string; Socket clientSkt = user.Value as Socket; if (!uName.Equals(userName) clientSkt.Send(_msgBuff); else if (_cmd = 01)/請求用戶列表 byte onlineBuff = Seria

16、lizeOnlineUserList(obj); /先發(fā)送響應(yīng)信號,用于客戶機的判斷,11表示服務(wù)發(fā)給客戶機的更新在線列表的命令 client.Send(new byte 1, 1 ); client.Send(onlineBuff); else if (_cmd = 02)/與服務(wù)器斷開連接 userMap.Remove(userName); string svrlog = string.Format(系統(tǒng)消息用戶【0】在【1】已斷開. 當前在線人數(shù):【2】rnrn, userName, DateTime.Now, userMap.Count); foreach (KeyValuePair

17、user in userMap) string uName = user.Key as string; Socket clientSkt = user.Value as Socket; clientSkt.Send(Encoding.Unicode.GetBytes(svrlog);/給其他用戶通知現(xiàn)在上線的用戶 smsg(lisWin, svrlog);/利用委托更新服務(wù)器顯示日志 Thread.CurrentThread.Abort();/終止為該客戶端開啟的線程 else/發(fā)送給指定用戶 string _receiver = Encoding.Unicode.GetString(_cmd

18、Buff).TrimEnd(0); byte _packetBuff = new bytemaxPacket; client.Receive(_packetBuff); if (userMap.ContainsKey(_receiver)/是否存在該接收者 /通過轉(zhuǎn)發(fā)表查找接收方的套接字 Socket receiverSkt = userMap_receiver as Socket; receiverSkt.Send(_packetBuff); else string sysMessage = string.Format(系統(tǒng)消息您剛才的內(nèi)容沒有發(fā)送成功。rn可能原因:用戶【0】已離線或者網(wǎng)絡(luò)

19、阻塞。rnrn, _receiver); client.Send(Encoding.Unicode.GetBytes(sysMessage); catch (SocketException) string svrlog = string.Format(系統(tǒng)消息用戶【0】的客戶端在【1】意外終止!當前在線人數(shù)【2】rnrn, userName, DateTime.Now, userMap.Count); smsg(lisWin, svrlog);/利用委托更新服務(wù)器顯示日志 /向所有客戶機發(fā)送系統(tǒng)消息 foreach (KeyValuePair user in userMap) string u

20、Name = user.Key as string; Socket clientSkt = user.Value as Socket; clientSkt.Send(Encoding.Unicode.GetBytes(svrlog); Thread.CurrentThread.Abort(); 負責顯示客戶端連接信息的服務(wù)器窗口的后臺處理代碼:using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.L

21、inq;using System.Text;using System.Windows.Forms;using System.Threading;using System.Net.Sockets;namespace TalkerServer public partial class ListenWindow : Form private Listener listener = null; private Thread listenThread = null; delegate void SetTextCallback(ListenWindow lisWin,string text); publi

22、c ListenWindow() InitializeComponent(); listener = new Listener(); private void btnListen_Click(object sender, EventArgs e) this.btnListen.Enabled = false; int port = this.listener.ListenPort ; if (int.TryParse(txtEndpoint.Text, out port) if (port 65535) MessageBox.Show(端口號不合法!, 提示, MessageBoxButton

23、s.OK, MessageBoxIcon.Information); return; this.listenThread = new Thread(new ThreadStart(this.ThreadProcSafe); this.listenThread.Start(); else MessageBox.Show(端口號不合法!,提示,MessageBoxButtons.OK,MessageBoxIcon.Information); return; public void showSvgMsg(ListenWindow lisWin ,string svrInfo) lisWin.txtC

24、onnInfo.Text = svrInfo; #region / / 1:訪問 Windows 窗體控件本質(zhì)上不是線程安全的。 / 2:如果有兩個或多個線程操作某一控件的狀態(tài),則可能會迫使該控件進入一種不一致的狀態(tài)。 / 3:如果從創(chuàng)建控件的線程之外的其他線程試圖更改控件的狀態(tài),一半情況下是不行的 / 4:以事件句柄創(chuàng)建一個以線程安全方式調(diào)用windows窗體控件的線程。 / public void ThreadProcSafe()/線程安全訪問控件 this.listener.Listen(SetText,this); private void SetText(ListenWindow l

25、isWin,string text) if (lisWin.txtConnInfo.InvokeRequired) SetTextCallback d = new SetTextCallback(SetText); lisWin.Invoke(d, new object this,text ); else lisWin.txtConnInfo.AppendText(text); #endregion private void btnStopListen_Click(object sender, EventArgs e) if (listener != null) if (listener.Tc

26、pListener != null) listener.TcpListener.Stop(); if (listener.UserMap.Count != 0) foreach (Socket socket in listener.UserMap.Values) socket.Shutdown(SocketShutdown.Both); listener.UserMap.Clear(); listener.UserMap = null; listener = null; this.btnListen.Enabled = true; 2.2客戶端主要代碼客戶端聊天窗口后臺代碼:using Sys

27、tem;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Net.Sockets;using System.Threading;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Bina

28、ry;using System.IO;using System.Collections.Specialized;namespace TalkClient public partial class TalkWindow : Form private string _username = null;/登陸用戶名 private int maxPacket = 2048;/2K的緩沖區(qū) private Thread receiveThread = null;/用于接收消息 private NetworkStream _nws = null;/網(wǎng)絡(luò)數(shù)據(jù)流 delegate void SetTextCa

29、llback(TalkWindow talkWin, string text); / / 處理接收到的消息 / private void MsgHandle() while (true)/無限循環(huán),不斷接收消息 byte packet = new bytemaxPacket; _nws.Read(packet, 0, packet.Length); string msg = string.Concat(packet0.ToString(), packet1.ToString(); if (msg = 11)/更新在線用戶列表 byte onlineBuff = new bytemaxPacke

30、t; int byteCnt = _nws.Read(onlineBuff, 0, onlineBuff.Length); IFormatter format = new BinaryFormatter(); MemoryStream stream = new MemoryStream(); stream.Write(onlineBuff, 0, byteCnt); stream.Position = 0; StringCollection onlineList = (StringCollection)format.Deserialize(stream); drpReceiver.Items.

31、Clear(); foreach (string onliner in onlineList) if (!onliner.Equals(_username) drpReceiver.Items.Add(onliner); else string displaytxt = Encoding.Unicode.GetString(packet); SetText(this,displaytxt);/添加到聊天內(nèi)容中 / / 從非創(chuàng)建該控件的線程訪問該控件,并且修改其Text屬性 / / / public void SetText(TalkWindow talkWin, string text) if

32、 (this.txtAllMsg.InvokeRequired) SetTextCallback stc = new SetTextCallback(SetText); talkWin.Invoke(stc, new object this,text ); else this.txtAllMsg.AppendText(text); private void btnSend_Click(object sender, EventArgs e) string localTxt = ;/本地顯示消息 string remoteTxt = ;/其它用戶顯示的消息 string msg = txtSelf

33、Msg.Text.Trim();/本人將要發(fā)送的消息 if (msg = string.Empty) MessageBox.Show(不能發(fā)送空消息,提示,MessageBoxButtons.OK,MessageBoxIcon.Information); return; /判斷選擇的聊天模式 if (drpTalkModem.SelectedIndex = 0)/悄悄話模式 string receiver = drpReceiver.Text; if (receiver = string.Empty) MessageBox.Show(請選擇發(fā)送悄悄話的人,若列表中為空,表明當前只有你一人在線!

34、, 提示, MessageBoxButtons.OK, MessageBoxIcon.Information); return; else localTxt = string.Format(私聊您在 0 對 1 說:rn2rnrn, DateTime.Now, receiver, msg); remoteTxt = string.Format(私聊0 在 1 對您說:rn2rnrn, _username, DateTime.Now, msg); _nws.Write(Encoding.Unicode.GetBytes(receiver), 0, Encoding.Unicode.GetByte

35、s(receiver).Length); else localTxt = string.Format(群聊您在 0 對所有人說:rn1rnrn, DateTime.Now, msg); remoteTxt = string.Format(群聊0 在 1 對所有人說:rn2rnrn, _username, DateTime.Now, msg); _nws.Write(new byte 0, 0 , 0, 2); _nws.Write(Encoding.Unicode.GetBytes(remoteTxt), 0, Encoding.Unicode.GetBytes(remoteTxt).Length); txtAllMsg.AppendText(localTxt);/添加發(fā)送的消息到聊天記錄里 txtSelfMsg.Clear();/清空剛編輯發(fā)送的消息 / / 聊天模式,選擇悄悄話,左邊的在線用戶列表可用,可以選擇里面的任意用戶進行聊天 / 選擇所有人,消息將會群發(fā)給所有人 / / / private void drpTalkModem_SelectedIndexChanged(object sender, Ev

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論