

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、<p><b> 實 驗 報 告</b></p><p><b> |</b></p><p><b> |</b></p><p> 實驗名稱 網絡聊天室的實現 </p><p> 課程名稱 計算機操作系統
2、 </p><p><b> |</b></p><p><b> |</b></p><p> 目 錄 </p><p> 設計原理———————————————————————4</p><p> 程序流程圖———————————
3、———————————9</p><p> 設計步驟———————————————————————10</p><p> 使用方法說明—————————————————————21</p><p> 實驗結果及分析————————————————————24</p><p><b> 設計原理</b></p
4、><p> 計算機網絡技術發(fā)展至今已經大大超越了人們當初的預想,無論是人們日常的工作還是學習,我們都越來越多的依靠到互聯網。各種實時性的聊天娛樂軟件也同時誕生,而且為我們的即時通訊帶來了眾多的方便,比如說大家所熟知的騰訊QQ、微軟的MSN、移動的Fetion等,都是做的比較成功的實時聊天工具。隨著網絡的日益普及,各種聊天工具也層出不窮,接下來的課程設計就是針對一個簡單的網絡聊天程序,利用MFC為開發(fā)工具,實現基本的
5、通訊功能。</p><p> 此程序主要分為兩部分:服務器端和客戶端。服務器端用于提供一個網絡端口,等待客戶端發(fā)出請求,登錄到此服務端,然后進行網絡通訊和消息的轉發(fā);客戶端可通過服務器端的IP地址發(fā)送連接請求,然后登陸聊天室。在服務器端的成員列表欄中會顯示在線的所有人名單,有人退出聊天室,成員列表會自動除名。服務器端同時也提供了成員之間的私聊功能,此時服務器端作為一個轉發(fā)站,進行消息的轉發(fā)。整個程序的主體使用了
6、CSocket類的方法,實現了網絡通訊聊天。</p><p> 整個程序設計為兩個部分:服務器 (ChatServer)和客戶端 (Chat)</p><p> 多人聊天的關鍵在于要將每個客戶端發(fā)送過來的消息分發(fā)給所有其他客戶端,為了解決這個問題,在服務器程序中建立一個套接口鏈表,用來保存所有與客戶端建立了連接的服務端口。下面描述了多人聊天的實現原理:</p><p
7、> 當客戶端Client N向對應的服務端口N發(fā)送了消息Message,服務端口N將Message復制給所有套接口列表(USERLIST)中的套接口緩沖區(qū),然后向每個服務端口發(fā)送WRITE消息,使每個服務端口將Message發(fā)送給對應的客戶端。這樣,所有客戶端就都獲得了Message消息,實現了多人聊天功能。</p><p> BOOL CClientSocketList::Sends(char *bu
8、ff,int n)</p><p> {CClientSocket *curr=Head;</p><p> while (curr)</p><p> {curr->Send(buff,n);</p><p> curr=curr->Next;}</p><p> return true;}&l
9、t;/p><p> USERLIST表時多人聊天程序的核心,它是一個動態(tài)變化的鏈表,為空表示沒有客戶端建立了連接,不為空時每個元素就代表有一個客戶端與服務器建立了連接。</p><p> 以下程序是私聊功能的實現:</p><p> BOOL CClientSocketList::OnlySend(char *buff,int n,int who)</p&g
10、t;<p><b> {</b></p><p> CClientSocket *curr=Head;</p><p> while (curr && who>0)</p><p> {curr=curr->Next;</p><p><b> who--;}
11、</b></p><p> curr->Send(buff,n);</p><p> return true;}</p><p> 以下是此程序的效果截圖:</p><p><b> 服務器端的效果截圖</b></p><p> 用戶“yq”的登錄界面</p>
12、;<p> 用戶“zxl”的登錄界面</p><p><b> 功能描述</b></p><p> 多人會話。此程序分為服務器端和客戶端,當客戶端要進入聊天室的時候,就必須通過網絡連接到服務端,以實現和其它客戶端的通訊功能。其中最簡單的一種通訊方式就是多人會話,運用多線程同時對多個用戶的信息進行監(jiān)聽,服務器通過轉發(fā)消息,讓所有人都可以得到消息,實現
13、多人會話。</p><p> 一對一會話。此程序的服務器端除了能夠提供多人會話的功能外,還提供了私人聊天功能,可以實現一對一的聊天。就是在消息轉發(fā)的時候,私聊的消息只發(fā)給私聊的對象,而其他人看不到此消息,但是此消息會通過服務器端轉發(fā),然后再到達目的客戶端。</p><p> 個性化的昵稱。為了區(qū)別用戶,此程序還允許用戶可以自定義個性化的昵稱。在用戶登錄的時候,用戶可以為自己設定一個昵稱
14、,以便在多人會話的時候作為身份識別。同時服務器端也會以此昵稱作為客戶端的登錄身份,服務器管理員,同樣也顯示在其他用戶的在線列表欄中。</p><p> 服務器登陸。服務器端開啟之后處于監(jiān)聽狀態(tài),多線程工作,接受每一個用戶的連接請求。而客戶端只需輸入服務器端的IP地址即可,端口在服務器端自動生成。</p><p><b> 操作系統關鍵字:</b></p>
15、;<p><b> 進程間通信;</b></p><p><b> 同步互斥;</b></p><p><b> 多線程操作</b></p><p><b> 設計步驟:</b></p><p> 本聊天程序實現工具為Visual
16、C++ 6.0 MFC,主要利用其中用于網絡編程的CSocket類實現網絡通訊功能。主要程序分為兩部分:</p><p> 服務器端,界面如下圖所示:</p><p><b> 主要代碼如下所示:</b></p><p> ?。?)、CChatRoomServerDlg函數用來對服務器端進行初始化</p><p>
17、 void CChatServerDlg::OnPaint() </p><p> {if (IsIconic())</p><p> {CPaintDC dc(this); // device context for painting</p><p> SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc
18、(), 0);</p><p> int cxIcon = GetSystemMetrics(SM_CXICON);</p><p> int cyIcon = GetSystemMetrics(SM_CYICON);</p><p> CRect rect;</p><p> GetClientRect(&rect);<
19、;/p><p> int x = (rect.Width() - cxIcon + 1) / 2;</p><p> int y = (rect.Height() - cyIcon + 1) / 2;</p><p> dc.DrawIcon(x, y, m_hIcon);}</p><p><b> else</b>
20、;</p><p> {CDialog::OnPaint();}</p><p><b> }</b></p><p> HCURSOR CChatServerDlg::OnQueryDragIcon()</p><p> {return (HCURSOR) m_hIcon;}</p><p&
21、gt;<b> //開始服務器按鈕</b></p><p> void CChatServerDlg::OnButtonStart() </p><p> {m_IDC_BUTTON_START.EnableWindow(FALSE);//讓開啟按鈕失效</p><p> if (!ListenSocket.Create(6400))/
22、/綁定端口</p><p> {AfxMessageBox("綁定端口失敗!");}</p><p> if (!ListenSocket.Listen())//服務器偵聽</p><p> {AfxMessageBox("偵聽失敗!");}</p><p> AfxMessageBox(&qu
23、ot;服務器開啟成功!");</p><p> CString tTmep;</p><p> tTmep="系統消息:服務器已開啟成功!";</p><p> m_ChatList.AddString(tTmep);</p><p> m_IDC_BUTTON_STOP.EnableWindow(TRU
24、E);//恢復停止按鈕}</p><p> void CChatServerDlg::OnButtonStop() </p><p> {m_IDC_BUTTON_STOP.EnableWindow(FALSE);</p><p> char s[30]="聊天服務器停止工作了??!";</p><p> Liste
25、nSocket.CCSL.Sends(s,30);//廣播聊天服務器停止消息</p><p> CClientSocket *p=ListenSocket.CCSL.Head;</p><p><b> while (p)</b></p><p> {p->Close();</p><p> ListenS
26、ocket.CCSL.Del(p);//釋放鏈表中的套接字</p><p> p=ListenSocket.CCSL.Head;}</p><p> ListenSocket.Close();</p><p> m_USER.ResetContent();//清楚服務器在線用戶列表</p><p> m_IDC_BUTTON_STAR
27、T.EnableWindow(TRUE);}</p><p> void CChaServerDlg::OnButtonSend() </p><p><b> {int n;</b></p><p> char message[1000];</p><p> UpdateData(TRUE);</p&g
28、t;<p> if (m_IDC_BUTTON_MESSAGE=="")</p><p> {MessageBox("請輸入消息??!","提示",MB_OK);}</p><p><b> else</b></p><p> {m_IDC_BUTTON_MESSA
29、GE="服務器端說:"+m_IDC_BUTTON_MESSAGE;</p><p> n=m_IDC_BUTTON_MESSAGE.GetLength();</p><p> sprintf(message,"%s",m_IDC_BUTTON_MESSAGE.GetBuffer(n));</p><p> message
30、[n]=0;</p><p> ListenSocket.CCSL.Sends(message,1000);}</p><p> m_IDC_BUTTON_MESSAGE="";</p><p> UpdateData(FALSE);}</p><p> (2)、CClientSocket函數用于管理用戶列表及會話
31、</p><p> void CClientSocket::OnReceive(int nErrorCode)</p><p> {char buff[1000];</p><p> char all_user[2000];</p><p> char name[20];</p><p><b>
32、int n;</b></p><p><b> int m;</b></p><p> n=this->Receive(buff,1000);</p><p> buff[n]=0;</p><p> char Flag[10];</p><p> for (int i
33、=0;i<8;i++)</p><p> {Flag[i]=buff[i];}</p><p> Flag[8]=0;</p><p> CChatRoomServerApp *pApp=(CChatRoomServerApp*)AfxGetApp();</p><p> CChatRoomServerDlg *pDlg=(CC
34、hatRoomServerDlg*)pApp->m_pMainWnd;</p><p> if (strcmp(Flag,"NEW_USER")==0)</p><p> {CString sTemp;</p><p> for (i=9;buff[i]!=0;i++)</p><p> {buff[i-9]
35、=buff[i];}</p><p> buff[i-9]=0;</p><p> sTemp.Format("%s",buff);</p><p> pDlg->m_USER.AddString(sTemp);</p><p> m=pDlg->m_USER.GetCount();</p>
36、<p> strcpy(all_user,"USERLIST");</p><p> for (i=0;i<m;i++)</p><p> {pDlg->m_USER.GetText(i,name);</p><p> strcat(all_user,name);</p><p> st
37、rcat(all_user,"|");}</p><p> strcat(buff,"進入聊天室");</p><p> List->Sends(all_user,strlen(all_user));}</p><p><b> else</b></p><p> {
38、if (strcmp(Flag,"CLOSEUSE")==0)</p><p> {CString sTemp;</p><p> for (i=9;buff[i]!=0;i++)</p><p> {buff[i-9]=buff[i];}</p><p> buff[i-9]=0;</p><
39、p> sTemp.Format("%s",buff);//離線用戶昵稱</p><p> m=pDlg->m_USER.GetCount();</p><p> for (i=0;i<m;i++)</p><p> {pDlg->m_USER.GetText(i,name);</p><p>
40、; if (strcmp(name,buff)==0)</p><p> {pDlg->m_USER.DeleteString(i);</p><p><b> }</b></p><p> //將新的在線用戶昵稱名單發(fā)給所有用戶</p><p> m=pDlg->m_USER.GetCount()
41、;</p><p> strcpy(all_user,"USERLIST");</p><p> for (i=0;i<m;i++)</p><p> {pDlg->m_USER.GetText(i,name);</p><p> strcat(all_user,name);</p>&l
42、t;p> strcat(all_user,"|");</p><p> strcat(buff,"離開聊天室!");</p><p> List->Sends(all_user,strlen(all_user));</p><p> List->Del(this);}</p><p
43、> else if (strcmp(Flag,"PrivChat")==0)//私聊</p><p> {CString sTemp;</p><p> for (i=9;buff[i]!='|';i++)</p><p> {buff[i-9]=buff[i];}</p><p> buf
44、f[i-9]=0;</p><p> sTemp.Format("%s",buff);</p><p> for (int k=i+1;buff[k]!=0;k++)</p><p> {buff[k-i-1]=buff[k];}</p><p> buff[k-i-1]=0;</p><p&g
45、t; m=pDlg->m_USER.GetCount();</p><p> for (i=0;i<m;i++)</p><p> {pDlg->m_USER.GetText(i,name);</p><p> if (strcmp(name,sTemp)==0)</p><p> {List->OnlySe
46、nd(buff,strlen(buff),i);}</p><p><b> }}</b></p><p><b> else</b></p><p> {List->Sends(buff,n);//將聊天信息群發(fā)給所有用戶}</p><p><b> }</b>
47、</p><p> CString sTemp;</p><p> sTemp.Format("收到:%s",buff);</p><p> pDlg->m_ChatList.AddString(sTemp);</p><p> pDlg->m_ChatList.SetTopIndex(pDlg->
48、;m_ChatList.GetCount()-1);</p><p> CSocket::OnReceive(nErrorCode);}</p><p> ?。?)、一下代碼用于設定用戶的多人會話與一對一會話</p><p> BOOL CClientSocketList::Add(CClientSocket *add)</p><p>
49、 {CClientSocket *tmp=Head;</p><p> if (!Head)</p><p> {Head=add;</p><p> return false;}</p><p> while (tmp->Next)</p><p> {tmp=tmp->Next;}</
50、p><p> tmp->Next=add;</p><p> return true;}</p><p> //從鏈表隊列中刪除Socket</p><p> BOOL CClientSocketList::Del(CClientSocket *d)</p><p> {CClientSocket *p1=
51、Head;</p><p> CClientSocket *p2;</p><p> if (!Head)</p><p> {return false;}</p><p> if (Head==d)</p><p> {Head=p1->Next;</p><p> p1-&
52、gt;Close();</p><p> delete p1;</p><p> return true;}</p><p> for (;p1->Next!=NULL;p1=p1->Next)</p><p> {if (p1->Next==d)</p><p> {p2=p1->N
53、ext;</p><p> p1->Next=p2->Next;</p><p> p2->Close();</p><p> delete p2;</p><p> return true;}}</p><p> return false;}</p><p> /
54、/向所有用戶發(fā)送消息</p><p> BOOL CClientSocketList::Sends(char *buff,int n)</p><p> {CClientSocket *curr=Head;</p><p> while (curr)</p><p> {curr->Send(buff,n);</p>
55、<p> curr=curr->Next;}</p><p> return true;}</p><p> //僅僅向私聊用戶who發(fā)送信息</p><p> BOOL CClientSocketList::OnlySend(char *buff,int n,int who)</p><p> {CClient
56、Socket *curr=Head;</p><p> while (curr && who>0)</p><p> {curr=curr->Next;</p><p><b> who--;}</b></p><p> curr->Send(buff,n);</p>
57、<p> return true;}</p><p> 客戶端,截圖如下所示:</p><p><b> 主要代碼:</b></p><p> void CChatDlg::OnConnectButton() //連接聊天室服務器</p><p> {// TODO: Add your contr
58、ol notification handler code here</p><p> UpdateData(TRUE);</p><p> char *nikename;</p><p> char *address;</p><p><b> int n;</b></p><p> i
59、f (!myServerSocket->Create())</p><p> {myServerSocket->Close();</p><p> AfxMessageBox("網絡創(chuàng)建錯誤?。?quot;);</p><p><b> return;}</b></p><p> n=m_I
60、DC_EDIT_ADDRESS.GetLength();</p><p> address=new char(n+1);</p><p> sprintf(address,"%s",m_IDC_EDIT_ADDRESS.GetBuffer(n));</p><p> address[n]=0;</p><p> n
61、=m_IDC_EDIT_NIKENAME.GetLength();</p><p> nikename=new char(n+1);</p><p> sprintf(nikename,"%s",m_IDC_EDIT_NIKENAME.GetBuffer(n));</p><p> nikename[n]=0;</p><
62、;p> if (!myServerSocket->Connect(address,6767))</p><p> {myServerSocket->Close();</p><p> AfxMessageBox("網絡連接錯誤,請檢查服務器地址。");</p><p><b> return; }</b&
63、gt;</p><p> m_BNSend.EnableWindow(TRUE);</p><p> m_BNExit.EnableWindow(TRUE);</p><p> myServerSocket->NikeName=nikename;</p><p><b> //發(fā)送新用戶昵稱</b><
64、/p><p> char message2[20];</p><p> strcpy(message2,"NEW_USER|");</p><p> strcat(message2,myServerSocket->NikeName);</p><p> if (myServerSocket->Send(me
65、ssage2,20))//——————————連接聊天室服務器</p><p> {AfxMessageBox("連接成功?。?quot;);}</p><p><b> else</b></p><p> {AfxMessageBox("網絡傳輸錯誤?。。?quot;);}}</p><p>
66、 void CChatRoomDlg::OnSendButton() </p><p> {// TODO: Add your control notification handler code here</p><p><b> int n;</b></p><p> char message[1000];</p>&l
67、t;p> CString to_name;</p><p> UpdateData(TRUE);</p><p> if (m_IDC_EDIT_MESSAGE=="")</p><p> {MessageBox("請輸入要發(fā)送的消息!","提示",MB_OK);}</p>&l
68、t;p><b> else</b></p><p> {if (m_SL==TRUE)//私聊</p><p> {if (m_USER.GetCurSel()>=0)</p><p> {m_USER.GetText(m_USER.GetCurSel(),to_name);</p><p> m_
69、IDC_EDIT_MESSAGE=myServerSocket->NikeName+m_IDC_EDIT_MESSAGE;</p><p> m_ChatList.AddString(m_IDC_EDIT_MESSAGE);</p><p> m_IDC_EDIT_MESSAGE="PrivChat|"+to_name+"|"+m_IDC_
70、EDIT_MESSAGE;</p><p> n=m_IDC_EDIT_MESSAGE.GetLength();</p><p> sprintf(message,"%s",m_IDC_EDIT_MESSAGE.GetBuffer(n));</p><p> message[n]=0;}</p><p><b&
71、gt; else</b></p><p> {AfxMessageBox("沒有私聊對象!");</p><p><b> return;}}</b></p><p><b> else</b></p><p> {m_IDC_EDIT_MESSAGE=my
72、ServerSocket->NikeName+m_IDC_EDIT_MESSAGE;</p><p> n=m_IDC_EDIT_MESSAGE.GetLength();</p><p> sprintf(message,"%s",m_IDC_EDIT_MESSAGE.GetBuffer(n));</p><p> message[n
73、]=0;}</p><p> if (myServerSocket->Send(message,n+1))</p><p> {m_IDC_EDIT_MESSAGE="";</p><p> UpdateData(FALSE);}</p><p><b> else</b></p&
74、gt;<p> {AfxMessageBox("網絡傳輸錯誤!");}}}</p><p> void CChatRoomDlg::OnExitButton() </p><p> {// TODO: Add your control notification handler code here</p><p> char
75、message2[20];</p><p> strcpy(message2,"CLOSEUSE|");</p><p> strcat(message2,myServerSocket->NikeName);</p><p> if (myServerSocket->Send(message2,20))//————————離開聊
76、天室</p><p><b> {}</b></p><p><b> else</b></p><p> {AfxMessageBox("網絡傳輸錯誤!");}</p><p> CDialog::OnOK();}</p><p> BOOL
77、CChatRoomDlg::GetMessage()//顯示聊天信息</p><p> {char buff[2000];</p><p> char name[20];</p><p> int count;</p><p> count=myServerSocket->Receive(buff,2000);</p>
78、;<p> buff[count]=0;</p><p> char Flag[10];</p><p> for (int i=0;i<8;i++)</p><p> {Flag[i]=buff[i];}</p><p> Flag[8]=0;</p><p> if (strcmp(
79、Flag,"USERLIST")==0)//新用戶昵稱列表</p><p> {m_USER.ResetContent();//清空列表</p><p> CString sTemp;</p><p><b> int j=8;</b></p><p> for (i=8;buff[i]!=0
80、;i++)</p><p> {if (buff[i]=='|')//昵稱分隔符號</p><p> {for (int m=0;j<i;j++,m++)</p><p> {name[m]=buff[j];}</p><p> name[m]='\0';</p><p>
81、 sTemp.Format("%s",name);//昵稱</p><p> m_USER.AddString(sTemp);</p><p> j=i+1;}} }</p><p> else//聊天信息</p><p> { m_ChatList.AddString(buff);}</p>&l
82、t;p> return true;}</p><p><b> 設計使用說明:</b></p><p> 此聊天程序的實現主要通過兩部分實現,一個是客戶端,一個是服務器端。服務器端可開啟服務,等待用戶登錄,實現消息的中轉發(fā)送;客戶端可以通過服務器端的IP地址登陸到聊天室,從而接入聊天網絡,實現局域互通。接下來就介紹一下此程序的使用過程:</p>
83、<p> 首先,服務器端應該開啟監(jiān)聽服務,等待客戶端的連接請求,并實時的給予響應。</p><p> 此時服務器端口處于監(jiān)聽狀態(tài),可以接受來自任何一個客戶端的連接請求。于是開啟客戶端進行連接。在客戶端口里面,可選項有:用戶昵稱,服務器IP地址,在線用戶列表,用戶私聊選項,消息發(fā)送窗口,消息接收窗口。用戶可輸入服務器端的IP地址進行連接請求,加入聊天室。同時也可以為自己創(chuàng)建一個個性化的昵稱,作為身
84、份標識。</p><p> 若在在聊天途中服務器出現異常或者斷開,在用戶端有如下的提示:</p><p> 下圖是用戶之間的聊天界面,注意在用戶聊天時,首先要選擇聊天的對象,然后發(fā)送消息,才可以與用戶之間進行私聊。</p><p><b> 結果及分析:</b></p><p> 此程序的功能達到了之前預想的可能
85、,通過服務器端的消息轉發(fā),實現了多用戶之間的群聊,和單個用戶之間的私聊,完整了一個簡單的網絡聊天軟件的功能。通過此次的實驗,也同時讓我對于CSocket網絡聊天類的使用有了更深入的了解,在關于網絡編程的方面也有了新的認識。雖然此程序的功能還比較的簡單,而且某些方面還沒能完善,但是,我相信我只是一個開始。</p><p> 現在就軟件自身還存在的問題羅列如下:</p><p> 成員列表
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 計算機網絡課程設計-- 用winsock實現聊天室的vc++程序設計
- 計算機網絡課程設計-- 用winsock實現聊天室的vc++程序設計
- vc++課程設計--聊天室程序設計
- 計算機網絡課程設計--聊天室
- 用vc++簡單的多線程聊天室課程設計
- vc++網絡聊天軟件課程設計
- [vc++畢設]vc做的聊天室+論文
- vc++設計簡單的聊天室畢業(yè)設計
- 計算機網絡課程設計--基于tcp協議編程的網絡聊天室
- 計算機操作系統課程設計
- vc++課程設計----用winsock實現聊天
- java網絡聊天室課程設計
- tcp課程設計--網絡聊天室
- 網絡編程課程設計---網絡聊天室
- 計算機操作系統課程設計報告
- 計算機操作系統課程設計報告
- 聊天室課程設計---聊天程序的設計和實現
- java課程設計--聊天室系統
- java課程設計---聊天室系統
- 網絡編程課程設計-java聊天室
評論
0/150
提交評論