《綜合課程設(shè)計(jì)》設(shè)計(jì)報(bào)告基于Socket的即時(shí)通訊系統(tǒng)
評(píng)閱教師評(píng)語:課程設(shè)計(jì)成績考勤成績實(shí)做成績報(bào)告成績總評(píng)成績指導(dǎo)教師簽名:綜合課程設(shè)計(jì)設(shè) 計(jì) 報(bào) 告論文題目: 基于Socket的即時(shí)通訊系統(tǒng) 學(xué)院(系): 電子信息與自動(dòng)化學(xué)院 班 級(jí): 721 學(xué)生姓名: 學(xué)號(hào) 指導(dǎo)教師: 時(shí)間: 2011 年 6月 7日 到 2011 年 6 月 17日一、 設(shè)計(jì)目的通過綜合課程設(shè)計(jì),使學(xué)生能夠運(yùn)用數(shù)字信號(hào)處理、信號(hào)與系統(tǒng)、通信原理、面向?qū)ο蟮某绦蛟O(shè)計(jì)、計(jì)算機(jī)通信網(wǎng)、通信協(xié)議開發(fā)及應(yīng)用等課程的知識(shí)來設(shè)計(jì)一個(gè)基于Socket的即時(shí)通訊系統(tǒng),培養(yǎng)學(xué)生的動(dòng)手能力以及分析問題、解決問題的能力。二、 設(shè)計(jì)內(nèi)容一個(gè)基于Socket的即時(shí)通訊系統(tǒng)的多人聊天軟件三、 設(shè)計(jì)要求(一)基本要求1 熟練掌握面向?qū)ο蟮某绦蛟O(shè)計(jì)方法;2 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)通訊,能進(jìn)行文字對(duì)話傳輸,包括客戶端與服務(wù)器端;3 能對(duì)系統(tǒng)參數(shù)進(jìn)行配置。(二)提高要求1、實(shí)現(xiàn)文件、圖片傳輸;2、語音對(duì)話(兩人及兩人以上);3、友好的對(duì)話界面。四、 設(shè)計(jì)原理1 TCP/IP簡(jiǎn)介 TCP/IP的歷史要追溯到70年代中期,當(dāng)時(shí)ARPA為了實(shí)現(xiàn)異種網(wǎng)之間的互連(interconnection)與互通(intercommunication),大力資助網(wǎng)間網(wǎng)技術(shù)的研究和開發(fā),于1977年到1979年推出目前形式的TCP/IP體系結(jié)構(gòu)和協(xié)議規(guī)范.到今天,TCP/IP技術(shù)以及Internet網(wǎng)間網(wǎng)已經(jīng)為廣大計(jì)算機(jī)工作者,機(jī)算機(jī)廠商和機(jī)算機(jī)用戶所接受.據(jù)統(tǒng)計(jì),到1990年,Internet以包含遍布?xì)W美的五千個(gè)活動(dòng)網(wǎng)絡(luò),超過三十萬臺(tái)機(jī)算機(jī).作為一種事實(shí)上的工標(biāo)準(zhǔn),TCP/IP技術(shù)方興未艾.2 TCP/IP的網(wǎng)絡(luò)分層結(jié)構(gòu) 對(duì)TCP/IP協(xié)議來說,TCP提供傳輸層服務(wù),IP提供網(wǎng)絡(luò)層服務(wù).TCP/IP協(xié)議組(或Internet協(xié)議組)的分層結(jié)構(gòu)及其與OSI模型的對(duì)應(yīng)關(guān)系如圖4所示.圖中有關(guān)協(xié)議的名稱及其基本含義如下: (1) TCP. 為傳輸控制協(xié)議(Transmission Control Protocol).它是提供給用戶進(jìn)程的一個(gè)可靠的全雙工字節(jié)流的面向連接的協(xié)議.大多數(shù)Internet應(yīng)用程序使用TCP.因?yàn)門CP使用IP,所以整個(gè)Internet協(xié)議組也常稱為TCP/IP協(xié)議組. (2) UDP. 為用戶數(shù)據(jù)報(bào)協(xié)議 (User Datagram Protocol). (3) ICMP. 為網(wǎng)間報(bào)文控制協(xié)議 (Internet Control Message Protocol). (4) IP. 網(wǎng)間協(xié)議 (Internet Protocol). IP協(xié)議是為TCP,UDP和ICMP提供分組發(fā)送服務(wù)協(xié)議. (5) ARP. 地址轉(zhuǎn)換協(xié)議. (6) RARP. 反向地址轉(zhuǎn)換協(xié)議.3 Socket編程界面 (1) Socket 原理 Socket編程界面由4BSD UNIX首先提出,目的是解決網(wǎng)間網(wǎng)進(jìn)程通信問題.Socket接口為進(jìn)程間通信提供了一種新的手段,它不但能用于同一機(jī)器中的進(jìn)程之間的通信,而且支持網(wǎng)絡(luò)通信功能.Socket具有類型,反應(yīng)了對(duì)用戶透明的通信特性. 一個(gè)完整的Socket連接用一個(gè)相關(guān)描述: 協(xié)議,本地地址,本地端口,遠(yuǎn)地地址,遠(yuǎn)地端口 Socket 是面向客戶-服務(wù)器模型而設(shè)計(jì)的,針對(duì)客戶和服務(wù)器程序提供不同的Socket系統(tǒng)調(diào)用. (2) Socket系統(tǒng)調(diào)用 不管Socket內(nèi)部機(jī)制如何,它提供給應(yīng)用程序員的最終界面是一組系統(tǒng)功能調(diào)用.下面,我們一一給出重要的Socket系統(tǒng)調(diào)用. 1. 創(chuàng)建 Socket - socket() 調(diào)用格式如下: sockid = socket (af,type,protocol) af : 地址族,指本socket所用地址類型. type : 類型,指創(chuàng)建socket的應(yīng)用程序所希望的通信服務(wù)器類型. protocol : 協(xié)議,指本socket請(qǐng)求的協(xié)議. 2. 指定本地地址 - bind()調(diào)用 bind()將本地socket地址與所創(chuàng)建的socket聯(lián)系起來,即將本socket地址賦予socket,以指定本地半相關(guān).bind()的作用相當(dāng)于給socket命名,調(diào)用格式為: bind (sockid,localaddr,addrlen) sockid : socket號(hào). localaddr : 本地socket地址. addrlen : 地址長度. 3. 建立socket連接 - connect () 與 accept ()調(diào)用 這兩個(gè)系統(tǒng)調(diào)用用于完成整個(gè)相關(guān)的建立.其中connect用于建立連接 .調(diào)用格為: connect (sockid,destaddr,addrlen) destaddr : 指向?qū)Ψ絪ocket地址(信宿地址)結(jié)構(gòu)的指針. accept : 用于面向連接的服務(wù)器,其調(diào)用格式為: newsock = accept (sockid,clientaddr,paddrlen) clientaddr : 指向客戶socket地址指針. paddrlen : 客戶socket地址長度. 4. listen() 調(diào)用 此調(diào)用用于面向連接服務(wù)器,表明它愿意接收連接,listen()在accept()之前調(diào)用,格式為: listen (sockid,quelen) quelen : 請(qǐng)求隊(duì)列長度. 5. 發(fā)送數(shù)據(jù) - write(),writev(),send()與sendto(),sendmsg() 用于socket數(shù)據(jù)發(fā)送的系統(tǒng)調(diào)用一共有五個(gè),其中三個(gè),write(),writev()和send()用于面向連接傳輸,其余兩個(gè)用于無連接傳輸.面向連接的調(diào)用可以不指定信宿地址,而無連接的調(diào)用必須指定.假如無連接socket的雙方均調(diào)用過connect(),可以認(rèn)為是建立有連接的socket,也可以面向連接調(diào)用發(fā)送數(shù)據(jù). 三個(gè)面向連接調(diào)用三者的格式大致相同: write (sockid,buff,bufflen) : 緩沖發(fā)送 writev (sockid,iovector,vectorlen) : 集中發(fā)送 send (sockid,buff,bufflen,flags) : 可控緩沖發(fā)送 其中buff指向發(fā)送緩沖區(qū)的指針,bufflen是發(fā)送緩沖區(qū)大小. 用于無連接數(shù)據(jù)發(fā)送的調(diào)用有兩個(gè): sendto (sockid,buff,bufflen,flags,dsadd,addrlen) sendmsg (sockid,message,flags):可控集中無連接發(fā)送. 6. 接收數(shù)據(jù) - read(),readv(),recv()與recvfrom(),recvmsg() 接收數(shù)據(jù)與發(fā)送數(shù)據(jù)系統(tǒng)調(diào)用是一一對(duì)應(yīng)的,兩者參數(shù)的最大區(qū)別是,前者buffer是一個(gè)指針,其所指單元初值為欲讀數(shù)據(jù)長度,調(diào)用后的值是實(shí)際讀出的值.4 客戶-服務(wù)器模型的Socket實(shí)現(xiàn)框架 1)客戶-服務(wù)器模型時(shí)序圖 下圖是面向連接客戶-服務(wù)器模型的典型時(shí)序圖 服務(wù)器 客戶 socket() socket() bind() bind() listen() accept() 等待客戶連接請(qǐng)求 阻塞 < connect() read() <> write() 2)服務(wù)器socket地址的確定在客戶-服務(wù)器模型中,所有的作用者都是客戶首先發(fā)起的(如連接請(qǐng)求,服務(wù)請(qǐng)求等),因此客戶必須要知道服務(wù)器socket地址,另外,客戶調(diào)用服務(wù)器之前,可以在命令行中給出服務(wù)器所在主機(jī)的域名,根據(jù)域名可以獲得服務(wù)器主機(jī)的地址,系統(tǒng)調(diào)用為:hp=gethostbyname(host).其中host可以是服務(wù)器主機(jī)域名,返回hp是一個(gè)指向主機(jī)地址結(jié)構(gòu)的指針。五、 軟件設(shè)計(jì)(附程序流程圖、源程序清單)1. 程序流程圖2.源程序清單void CChatRoomDlg:DlgAllInit()CheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_CLIENT);SetDlgItemText(IDC_IP_ADDR, _T("127.0.0.1"); / 初始化ip地址為本機(jī)地址。SetDlgItemText(IDC_CONNECT_PORT, _T("5566"); / 初始化端口。SetDlgItemText(IDC_LISTEN_PORT, _T("5566");EnableWindow(IDC_STOP_CLIENT, FALSE);EnableWindow(IDC_LISTEN_PORT, FALSE);EnableWindow(IDC_STOP_SERVER, FALSE);EnableWindow(IDC_START_SERVER, FALSE);EnableWindow(IDC_STATIC_LISTEN_PORT, FALSE); / 初始化按鍵啟用or禁用。EnableWindow(IDC_SENDMSG, FALSE);BOOL CChatRoomDlg:EnableWindow(UINT uID, BOOL bEnable)return GetDlgItem(uID)->EnableWindow(bEnable);void CChatRoomDlg:ExtendDiaog(BOOL bShow)static CRect m_DlgRectLarge(0, 0, 0, 0);static CRect m_DlgRectSmall(0, 0, 0, 0);static CRect m_GroupRectLarge(0, 0, 0, 0);static CRect m_GroupRectSmall(0, 0, 0, 0); / 設(shè)置 窗口大小 if ( m_DlgRectLarge.IsRectNull() ) GetWindowRect(&m_DlgRectLarge);m_DlgRectSmall = m_DlgRectLarge;m_DlgRectSmall.right -= 220;:GetWindowRect(GetDlgItem(IDC_FRAME)->GetSafeHwnd(), &m_GroupRectLarge);m_GroupRectSmall = m_GroupRectLarge;m_GroupRectSmall.right -= 220; / 設(shè)置 窗口 伸縮大小范圍if ( bShow ) bShowAll = TRUE;SetWindowPos(NULL, 0, 0, m_DlgRectLarge.Width(), m_DlgRectLarge.Height(), SWP_NOZORDER | SWP_NOMOVE);:SetWindowPos(GetDlgItem(IDC_FRAME)->GetSafeHwnd(), NULL, 0, 0, m_GroupRectLarge.Width(), m_GroupRectLarge.Height(), SWP_NOZORDER | SWP_NOMOVE);elsebShowAll = FALSE;SetWindowPos(NULL, 0, 0, m_DlgRectSmall.Width(), m_DlgRectSmall.Height(), SWP_NOZORDER | SWP_NOMOVE);:SetWindowPos(GetDlgItem(IDC_FRAME)->GetSafeHwnd(), NULL, 0, 0, m_GroupRectSmall.Width(), m_GroupRectSmall.Height(), SWP_NOZORDER | SWP_NOMOVE);void CChatRoomDlg:OnBnClickedNetset()if ( bShowAll ) ExtendDiaog(FALSE);elseExtendDiaog(TRUE); / 設(shè)置按鍵“網(wǎng)絡(luò)設(shè)置”的作用void CChatRoomDlg:OnBnClickedStartServer()m_hListenThread = CreateThread(NULL, 0, ListenThreadFunc, this, 0, NULL);void CChatRoomDlg:ShowMsg(CString strMsg)m_MsgEdit.SetSel(-1, -1);m_MsgEdit.ReplaceSel(strMsg+_T("rn");void CChatRoomDlg:RemoveClientFromArray(CClientItem in_Item)for( int idx = 0; idx <m_ClientArray.GetCount(); idx+ ) CClientItem tItem = m_ClientArray.GetAt(idx);if ( tItem.m_Socket = in_Item.m_Socket &&tItem.hThread = in_Item.hThread &&tItem.m_strIp = in_Item.m_strIp ) m_ClientArray.RemoveAt(idx); void CChatRoomDlg:OnBnClickedSendmsg()CString strMsg;GetDlgItemText(IDC_INPUT_MSG, strMsg);if ( m_bIsServer = TRUE ) strMsg = _T("張智超的服務(wù)器:>") + strMsg;ShowMsg(strMsg);SendClientsMsg(strMsg);else if (m_bIsServer = FALSE) CString strTmp = _T("張智超的客戶端:>") + strMsg;ShowMsg(strTmp);int iSend = send(m_ConnectSock, (char *)strMsg.GetBuffer(), strMsg.GetLength()*sizeof(TCHAR), 0);strMsg.ReleaseBuffer();elseAfxMessageBox(_T("請(qǐng)您先進(jìn)入聊天室!");SetDlgItemText(IDC_INPUT_MSG, _T(""); / socket 基本應(yīng)用void CChatRoomDlg:OnBnClickedStartClient()m_hConnectThred = CreateThread(NULL, 0, ConnectThreadFunc, this, 0, NULL);void CChatRoomDlg:SendClientsMsg(CString strMsg, CClientItem *pNotSend)TCHAR szBufMAX_BUF_SIZE = 0;_tcscpy_s(szBuf, MAX_BUF_SIZE, strMsg);for( INT_PTR idx = 0; idx < m_ClientArray.GetCount(); idx+ ) if ( !pNotSend | pNotSend->m_Socket != m_ClientArray.GetAt(idx).m_Socket | pNotSend->hThread != m_ClientArray.GetAt(idx).hThread |pNotSend->m_strIp != m_ClientArray.GetAt(idx).m_strIp) send(m_ClientArray.GetAt(idx).m_Socket, (char *)szBuf, _tcslen(szBuf)*sizeof(TCHAR), 0);void CChatRoomDlg:OnEnChangeInputMsg()CString strMsg;GetDlgItemText(IDC_INPUT_MSG, strMsg);if ( strMsg.IsEmpty() ) EnableWindow(IDC_SENDMSG, FALSE);elseEnableWindow(IDC_SENDMSG);void CChatRoomDlg:StopClient()bShutDown = TRUE;DWORD dwRet = WaitForSingleObject(m_hConnectThred, 1000);if ( dwRet != WAIT_OBJECT_0 ) TerminateThread(m_hConnectThred, -1);closesocket(m_ConnectSock);m_hConnectThred = NULL;m_ConnectSock = INVALID_SOCKET;m_bIsServer = -1;bShutDown = FALSE;void CChatRoomDlg:StopServer()UINT nCount = m_ClientArray.GetCount();HANDLE *m_pHandles = new HANDLEnCount+1;m_pHandles0 = m_hListenThread;for( int idx = 0; idx < nCount; idx+ ) m_pHandlesidx+1 = m_ClientArray.GetAt(idx).hThread;bShutDown = TRUE;DWORD dwRet = WaitForMultipleObjects(nCount+1, m_pHandles, TRUE, 1000);if ( dwRet != WAIT_OBJECT_0 ) for( INT_PTR i = 0; i < m_ClientArray.GetCount(); i+ ) TerminateThread(m_ClientArray.GetAt(i).hThread, -1);closesocket(m_ClientArray.GetAt(i).m_Socket);TerminateThread(m_hListenThread, -1);closesocket(m_ListenSock);delete m_pHandles;m_hListenThread = NULL;m_ListenSock = INVALID_SOCKET;m_bIsServer = -1;bShutDown = FALSE;void CChatRoomDlg:OnBnClickedStopClient()StopClient();ShowMsg(_T("停止客戶端成功!");EnableWindow(IDC_START_CLIENT);EnableWindow(IDC_STOP_CLIENT, FALSE);void CChatRoomDlg:OnBnClickedStopServer()StopServer();ShowMsg(_T("停止服務(wù)器成功!");EnableWindow(IDC_START_SERVER);EnableWindow(IDC_STOP_SERVER, FALSE);void CChatRoomDlg:OnBnClickedRadioClient()int iRet = -1;if ( m_bIsServer = TRUE ) int iRet = MessageBox(_T("您是聊天室的服務(wù)器端,如果您退出,所有的客戶端都將掉線!rn您確定退出嗎?"), _T("提示"), MB_OKCANCEL | MB_ICONWARNING);if ( iRet = IDOK ) StopServer();elseCheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_SERVER);if ( iRet = IDOK | m_bIsServer = -1 ) EnableWindow(IDC_IP_ADDR);EnableWindow(IDC_CONNECT_PORT);EnableWindow(IDC_STATIC_SERVER_IP);EnableWindow(IDC_STATIC_SERVER_PORT);EnableWindow(IDC_START_CLIENT);EnableWindow(IDC_STOP_CLIENT, FALSE);EnableWindow(IDC_LISTEN_PORT, FALSE);EnableWindow(IDC_STOP_SERVER, FALSE);EnableWindow(IDC_START_SERVER, FALSE);EnableWindow(IDC_STATIC_LISTEN_PORT, FALSE);void CChatRoomDlg:OnBnClickedRadioServer()int iRet = -1;if ( m_bIsServer = FALSE ) int iRet = MessageBox(_T("您正在聊天室中,確定退出嗎?"), _T("提示"), MB_OKCANCEL | MB_ICONWARNING);if ( iRet = IDOK ) StopClient();elseCheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_CLIENT);if ( iRet = IDOK | m_bIsServer = -1) EnableWindow(IDC_LISTEN_PORT);EnableWindow(IDC_STOP_SERVER, FALSE);EnableWindow(IDC_START_SERVER);EnableWindow(IDC_STATIC_LISTEN_PORT);EnableWindow(IDC_IP_ADDR, FALSE);EnableWindow(IDC_CONNECT_PORT, FALSE);EnableWindow(IDC_STATIC_SERVER_IP, FALSE);EnableWindow(IDC_STATIC_SERVER_PORT, FALSE);EnableWindow(IDC_START_CLIENT, FALSE);EnableWindow(IDC_STOP_CLIENT, FALSE);void CChatRoomDlg:OnBnClickedCancel()if ( m_bIsServer = TRUE ) StopServer();else if ( m_bIsServer = FALSE ) StopClient();OnCancel();void CChatRoomDlg:OnBnClickedOther()CPoint pt;CRect mRect;CMenu mMenu, *pMenu = NULL;GetDlgItem(IDC_OTHER)->GetWindowRect(&mRect);pt = mRect.BottomRight();pt.y = mRect.top+10;mMenu.LoadMenu(IDR_MENU1);pMenu = mMenu.GetSubMenu(0);pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);BOOL CChatRoomDlg:TrayMyIcon(BOOL bAdd)BOOL bRet = FALSE;NOTIFYICONDATA tnd;tnd.cbSize = sizeof(NOTIFYICONDATA);tnd.hWnd = GetSafeHwnd();tnd.uID = IDR_MAINFRAME;if ( bAdd = TRUE ) tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;tnd.uCallbackMessage = WM_TRAYICON_MSG;tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME);_tcscpy_s(tnd.szTip, sizeof(tnd.szTip), _T("聊天室v1.0");ShowWindow(SW_MINIMIZE);ShowWindow(SW_HIDE);bRet = Shell_NotifyIcon(NIM_ADD, &tnd);elseShowWindow(SW_SHOWNA);SetForegroundWindow();bRet = Shell_NotifyIcon(NIM_DELETE, &tnd);return bRet;void CChatRoomDlg:OnMenuTrayinco()TrayMyIcon();LRESULT CChatRoomDlg:OnTrayCallBackMsg(WPARAM wparam, LPARAM lparam)switch(lparam)case WM_RBUTTONUP:CMenu mMenu, *pMenu = NULL;CPoint pt;mMenu.LoadMenu(IDR_MENU2);pMenu = mMenu.GetSubMenu(0);GetCursorPos(&pt);SetForegroundWindow();pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);break;case WM_LBUTTONDBLCLK:ShowWindow(SW_RESTORE);SetForegroundWindow();TrayMyIcon(FALSE);break; 3. 附錄:課程設(shè)計(jì)中要用到的Winsock函數(shù)WSAStartup初始化socket庫WSACleanup結(jié)束socket庫的使用socket為所要進(jìn)行的網(wǎng)絡(luò)通信建立標(biāo)識(shí)符connect連接到遠(yuǎn)程主機(jī)closesocket結(jié)束通信,關(guān)閉標(biāo)識(shí)符bind將IP地址、TCP端口號(hào)與套接字標(biāo)識(shí)符綁定listen將接受套接字置于被動(dòng)模式,將服務(wù)器置于偵聽狀態(tài),并指定允許的連接數(shù)accept接受下一個(gè)呼入的連接recv接收傳入的TCP數(shù)據(jù)recvfrom接收傳入的UDP數(shù)據(jù)select在指定的套接字集準(zhǔn)備好接收數(shù)據(jù)前一直等待send發(fā)送TCP數(shù)據(jù)sendto發(fā)送UDP數(shù)據(jù)shutdown釋放TCP連接getpeername從套接字中獲取對(duì)等方的端口地址setsocketopt獲取當(dāng)前套接字的可變選項(xiàng)gethostbynameinet_addr把域名轉(zhuǎn)換成網(wǎng)絡(luò)IP地址把用點(diǎn)分十進(jìn)制表示的IP地址轉(zhuǎn)換成網(wǎng)絡(luò)IP地址getservbynamegetprotobyname獲得服務(wù)器的端口號(hào)把TCP、UDP轉(zhuǎn)換成相應(yīng)的服務(wù)號(hào)碼(interger)六、 調(diào)試過程測(cè)試的目的是為了發(fā)現(xiàn)功能是否達(dá)到,或者是否有更多的缺陷。當(dāng)兩個(gè)客戶端在建立連接時(shí),出現(xiàn)過程序假死異常。分析代碼發(fā)現(xiàn),線程調(diào)度出錯(cuò),接收消息線程th還未創(chuàng)建和啟動(dòng),監(jiān)聽線程wait已經(jīng)被銷毀了。修改代碼,給出兩種解決辦法:(1)在th線程的執(zhí)行方法中,將wait線程銷毀;在th線程銷毀前,重新開啟wait線程。(2)wait線程不銷毀。設(shè)置一bool類型變量isconnected,當(dāng)已經(jīng)建立連接后,isconnected=true,若再有其他的連接請(qǐng)求到達(dá),自動(dòng)將其他連接請(qǐng)求拒絕。連接斷開后,重置isconnected=false,將處理移交給用戶。我采用了第一種方法,調(diào)試之后,問題解決。在程序退出時(shí),常常發(fā)生錯(cuò)誤,異常退出,造成表面上看程序已結(jié)束,但卻仍然駐留在內(nèi)存中的現(xiàn)象。經(jīng)過反復(fù)分析代碼,最終確定問題出在程序退出處理流程上,通過修改和調(diào)試,問題解決。軟件圖示七、 實(shí)驗(yàn)結(jié)果分析整個(gè)開發(fā)過程中,共歷經(jīng)多次相互斷開、連接測(cè)試,聊天模塊終于可以正常運(yùn)行。借助在文本聊天模塊開發(fā)過程中積累的經(jīng)驗(yàn),較順利的完成了文件傳輸模塊的開發(fā)。通過在總集成后的程序的各個(gè)流程中添加消息提示框顯示程序內(nèi)部數(shù)據(jù)、對(duì)象的狀態(tài),并插入斷點(diǎn)進(jìn)行單步跟蹤發(fā)現(xiàn)各模塊工作正常,數(shù)據(jù)也未發(fā)生異?,F(xiàn)象。(1)程序啟動(dòng)之后就能看到當(dāng)前哪些機(jī)器在線,哪些可以與之進(jìn)行對(duì)等通信。(2)一旦有某個(gè)網(wǎng)內(nèi)的機(jī)器上線了,要有即時(shí)通知,并能及時(shí)更新用戶界面中的用戶列表。(3)當(dāng)雙擊某個(gè)列表項(xiàng)的時(shí)候,要彈出聊天對(duì)話框,可以在其中編輯要發(fā)送的聊天信息,并進(jìn)行發(fā)送。(4)聊天界面要人性化,下面是發(fā)送框,上面有已有聊天記錄,并借助滾動(dòng)條看到當(dāng)次所有的聊天記錄。(5)當(dāng)有遠(yuǎn)程用戶向本機(jī)發(fā)送文件的時(shí)候,要彈出一個(gè)消息提示框,提示本機(jī)用戶,可以選擇接收或者拒絕。(6)當(dāng)用戶覺得有必要保存聊天記錄時(shí),提供一個(gè)簡(jiǎn)單的聊天記錄保存功能。(7)文件傳輸過程中,應(yīng)該有當(dāng)前傳輸狀態(tài)提示,并能夠?qū)鬏敽臅r(shí)等進(jìn)行計(jì)算,作為當(dāng)前網(wǎng)絡(luò)狀態(tài)的一種反饋。經(jīng)檢查,當(dāng)用戶輸入無效操作時(shí),系統(tǒng)總是能檢測(cè)到無效操作,對(duì)用戶進(jìn)行相應(yīng)的信息反饋,并合理的做出內(nèi)部處理。當(dāng)系統(tǒng)本身發(fā)生錯(cuò)誤,比如網(wǎng)絡(luò)初始化失敗,綁定套接字失敗,數(shù)據(jù)讀取失敗等,都會(huì)進(jìn)行相對(duì)應(yīng)的正確處理。八、 體會(huì)和建議通過這些時(shí)間的開發(fā)設(shè)計(jì),開發(fā)基于Socket的聊天系統(tǒng)已經(jīng)可以按照預(yù)定要求實(shí)現(xiàn)功能,完全實(shí)現(xiàn)了聊天、文件傳輸?shù)裙δ堋kS著科技的發(fā)展和社會(huì)的進(jìn)步,聊天系統(tǒng)將需要得到進(jìn)一步改善,相應(yīng)的功能模塊也應(yīng)相應(yīng)的增加,比如多媒體方面的內(nèi)容,以滿足用戶需求。通過此次的論文,我學(xué)到了很多知識(shí),跨越了傳統(tǒng)方式下的教與學(xué)的體制束縛,在論文的寫作過程中,通過查資料和搜集有關(guān)的文獻(xiàn),培養(yǎng)了自學(xué)能力和動(dòng)手能力。并且由原先的被動(dòng)的接受知識(shí)轉(zhuǎn)換為主動(dòng)的尋求知識(shí),這可以說是學(xué)習(xí)方法上的一個(gè)很大的突破。在以往的傳統(tǒng)的學(xué)習(xí)模式下,我們可能會(huì)記住很多的書本知識(shí),但是通過畢業(yè)論文,我們學(xué)會(huì)了如何將學(xué)到的知識(shí)轉(zhuǎn)化為自己的東西,學(xué)會(huì)了怎么更好的處理知識(shí)和實(shí)踐相結(jié)合的問題。在論文的寫作過程中也學(xué)到了做任何事情所要有的態(tài)度和心態(tài),首先做學(xué)問要一絲不茍,對(duì)于發(fā)展過程中出現(xiàn)的任何問題和偏差都不要輕視,要通過正確的途徑去解決,在做事情的過程中要有耐心和毅力,不要一遇到困難就達(dá)退堂鼓,只要堅(jiān)持下去就可以找到思路去解決問題的。而且要學(xué)會(huì)與人合作,這樣做起事情來就可以事倍功半。 總之,此次課設(shè)的寫作過程,我收獲了很多,即為將來的人生之路做好了一個(gè)很好的鋪墊。 九、 參考文獻(xiàn)1 Karli Watson,Christian Nagel等.C入門經(jīng)典(第3版)M.北京:清華大學(xué)出版社.2004.2 宋振會(huì).SQL Server 2000中文版基礎(chǔ)教程M.北京:清華大學(xué)出版社.2005.3 Karli Watson等.Beginning Visual C# 2005M.北京:清華大學(xué)出版.社.2005.4 Jim Arlow Ila Neustadt.UML和統(tǒng)一過程M.北京:機(jī)械工業(yè)出版社.2003.2.5 佩里.C#和.NET核心技術(shù)M.北京:機(jī)械工業(yè)出版社.2006.7.6 天極網(wǎng)新技術(shù)研究室.ASP.NET完全入門M.北京:重慶出版社.2001.7 Scott Worley.ASP.NET技術(shù)內(nèi)幕M.北京:人民郵電出版社.2002.