




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第8章 網(wǎng)絡(luò)聊天編程第一部分 8.1 為應(yīng)用系統(tǒng)加入Socket8.2 編寫聊天模塊前的準(zhǔn)備8.3 編寫聊天模塊代碼第二部分 知識點(diǎn)鏈接L8.1 為應(yīng)用系統(tǒng)加入SocketL8.2 編寫聊天模塊代碼1第8章 網(wǎng)絡(luò)聊天編程系統(tǒng)功能:單擊菜單中的“交談”“對話”,彈出“對話(Socket聊天)”對話框,單擊“誰在線上”可以搜索工作組中所有用戶的計(jì)算機(jī)名,雙擊一個(gè)計(jì)算機(jī)名,該計(jì)算機(jī)名即顯示在左邊文本框中,單擊空白文本區(qū),單擊“我要上線”可上線等待來自其他用戶發(fā)送的數(shù)據(jù)并在文本框中顯示,否則不能接收消息,但能夠給已上線的用戶發(fā)送消息。圖8.1 雙方聊天2第一部分 應(yīng)用實(shí)踐8.1 為應(yīng)用系統(tǒng)加入Sock
2、et支持為MFC程序加入Socket支持一般有兩種方法,第一種是在用MFC AppWizard(exe)創(chuàng)建一個(gè)單文檔應(yīng)用程序時(shí),在向?qū)У牡?步選中Windows Sockets,如圖8.2所示。圖8.2 Windows Sockets支持38.1 為應(yīng)用系統(tǒng)加入Socket支持為MFC程序加入Socket支持一般有兩種方法,第一種是在用MFC AppWizard(exe)創(chuàng)建一個(gè)單文檔應(yīng)用程序時(shí),在向?qū)У牡?步選中Windows Sockets,如圖8.2所示。(1)打開工程,切換到,雙擊打開頭文件StdAfx.h,在其中加入一行:#include / MFC socket extensio
3、ns(2)mpr.lib這個(gè)庫里面封裝了Windows Networking(Wnet)函數(shù),這是一組網(wǎng)絡(luò)控制函數(shù),比如可以利用這些函數(shù)來列舉局域網(wǎng)內(nèi)所有機(jī)器名稱,IP地址以及其他相關(guān)信息。為了使用這些函數(shù)需要在StdAfx.h中加入一行:#pragma comment(lib,mpr)(3)切換到ClassView,打開CXSCJApp下的InitInstance函數(shù),在函數(shù)體最前面添加如下代碼以初始化Sockets:BOOL CXSCJApp:InitInstance()if (!AfxSocketInit()/ 是否初始化成功AfxMessageBox(Windows通信端口初始化失敗)
4、;return FALSE;48.2 編寫聊天模塊前的準(zhǔn)備(1)設(shè)置界面如圖8.3所示,新建對話框,設(shè)置標(biāo)題為Sockets聊天,ID為IDD_P2PCHAT,并在菜單上添加相應(yīng)的項(xiàng)如“對話”,并編寫彈出本對話框的命令代碼。 圖8.3 “設(shè)置Socket聊天”對話框58.2 編寫聊天模塊前的準(zhǔn)備添加“對話”菜單項(xiàng)ID_P2PCHAT的COMMAND消息到CXSCJView類中,代碼如下:void CXSCJView:OnP2pchat()/ TODO: Add your command handler code hereCDlgP2P myDlgP2P;myDlgP2P.DoModal();在
5、XSCJView.cpp中添加頭文件:#include DlgP2P.h(2)設(shè)置接收文本框IDC_SHOWSTR控件的屬性設(shè)置如圖8.4(左)所示,設(shè)置發(fā)送文本框IDC_SENDSTR的屬性如圖8.4(右)所示。圖8.4 設(shè)置編輯框的Styles屬性68.2 編寫聊天模塊前的準(zhǔn)備(3)打開列表控件的屬性對話框,將“查看”選為“小圖標(biāo)”,利于網(wǎng)絡(luò)聊天時(shí)各在線用戶名的完全顯示。單擊編排(Layout)測試(Test)后顯示界面如圖8.5所示。圖8.5 聊天模塊界面78.3 編寫聊天模塊代碼(1)為對話框新建類CDlgP2P,為控件添加關(guān)聯(lián)變量如圖8.6所示。圖8.6 設(shè)置控件關(guān)聯(lián)變量88.3 編
6、寫聊天模塊代碼(2)在對話框類CDlgP2P 的頭文件DlgP2P.h中加入變量和函數(shù)聲明。class CDlgP2P : public CDialog / Construction public: CDlgP2P(CWnd* pParent = NULL); / standard constructor CString GetIP(CString username); / 得到目標(biāo)機(jī)器IP void GetName(char Temp64); / 取得本機(jī)名 bool connectFlag ;/ 網(wǎng)絡(luò)連接標(biāo)識 void ShowRecvData(); / 顯示接收的數(shù)據(jù) void GetL
7、anActiveComputer(); / 獲取本地活動(dòng)計(jì)算機(jī)機(jī)器名稱 ;98.3 編寫聊天模塊代碼(3)在DlgP2P.cpp文件中加入全局變量如下:static int CreatedFlag=0;/ 是否已建立服務(wù)器SOCKET m_socket,m_hSocket;/ 建立套接字描述符sockaddr_in m_addr; / sockaddr_in結(jié)構(gòu)為套接字儲存套接字地址信息sockaddr_in m_raddr;sockaddr_in m_caddr;char *message=NULL;/ 聊天內(nèi)容接收框中的消息變量char *name=NULL;/ 聊天內(nèi)容接收框中的主機(jī)名變
8、量int nItem;/ CList控件中顯示內(nèi)容(主機(jī)名)的序號CString changstr;/ 中間變量CString strname;/ 同上UINT AcceptThread(LPVOID lpvoid);/ 接收線程SOCKET m_cSocket; / 客戶端Socket108.3 編寫聊天模塊代碼(4)取得本機(jī)名。void CDlgP2P:GetName(char Temp64) / 取本機(jī)(Local Machine)的主機(jī)名(即Windows中的本機(jī)計(jì)算機(jī)名)gethostname(Temp,64);(5)添加WM_INITDIALOG消息,用本機(jī)用戶名初始化全局變量ch
9、angstr。BOOL CDlgP2P:OnInitDialog() CDialog:OnInitDialog();/ TODO: Add extra initialization herechar localname64;GetName(localname);changstr=localname;return TRUE; / return TRUE unless you set the focus to a control / EXCEPTION: OCX Property Pages should return FALSE118.3 編寫聊天模塊代碼(6)在DlgP2P.cpp中添加Get
10、LanActiveComputer函數(shù),用枚舉的方法找到局域網(wǎng)里所有打開的機(jī)器。該函數(shù)的實(shí)現(xiàn)代碼中用到了幾個(gè)枚舉網(wǎng)絡(luò)資源的函數(shù),其中包括:WnetOpenEnum函數(shù)、WnetEnumResource函數(shù)和WnetCloseEnum函數(shù)。(7)根據(jù)計(jì)算機(jī)名得到IP地址。CString CDlgP2P:GetIP(CString username)CString hostaddr;struct hostent *hostname=gethostbyname(username);for(int i=0;hostname!=NULL&hostname-h_addr_listi;i+)hostaddr
11、=inet_ntoa(*(struct in_addr *)hostname-h_addr_listi);/ 得到的hostname是以網(wǎng)絡(luò)字節(jié)順序存儲的,要用inet_ntoa轉(zhuǎn)換得到IP點(diǎn)數(shù)形式return hostaddr;128.3 編寫聊天模塊代碼(8)創(chuàng)建ShowRecvData(),該函數(shù)負(fù)責(zé)將接收到的數(shù)據(jù)顯示在文本接收框中。void CDlgP2P:ShowRecvData()CString tempstr;tempstr=;if(name!=NULL&message!=NULL)tempstr=name;m_showstr=message;m_showstr=tempstr+
12、:+m_showstr; m_show.SetWindowText(m_showstr); / 顯示計(jì)算機(jī)名和它發(fā)送的消息message=NULL;name=NULL;(9)編寫線程AcceptThread,作用是接收來自多個(gè)客戶端的連接并發(fā)送數(shù)據(jù)。該線程參數(shù)為OnCreathost()傳來的對話框指針,根據(jù)該指針可以對聊天對話框中顯示接收數(shù)據(jù)的IDC_SHOWSTR文本框進(jìn)行操作。138.3 編寫聊天模塊代碼(10)為“我要上線”按鈕添加OnCreathost()事件。編寫代碼時(shí),需要用到許多Sockets編程常用函數(shù),包括:sockets()、bind()、listen()、connect
13、()、accept()、send()、recv()和closesockets。主要功能是打開Socket,綁定IP和端口號,開始監(jiān)聽,啟動(dòng)線程AcceptThread接受數(shù)據(jù)。148.3 編寫聊天模塊代碼(11)為ListCtrl控件IDC_USER添加雙擊事件NM_DBLCLK。void CDlgP2P:OnDblclkUser(NMHDR* pNMHDR, LRESULT* pResult) / TODO: Add your control notification handler code herePOSITION pos;m_showname.SetWindowText();nItem
14、=0;pos=m_List.GetFirstSelectedItemPosition();/ 取第一個(gè)選擇項(xiàng)的positonif(pos=NULL)return ;elsewhile(pos)/ 如果用戶選擇了多項(xiàng),則取最后選擇的一項(xiàng)nItem=m_List.GetNextSelectedItem(pos); m_name=m_List.GetItemText(nItem,0);UpdateData(FALSE); / 傳到“發(fā)送計(jì)算機(jī)”編輯框中,方向是變量到控件*pResult = 0;158.3 編寫聊天模塊代碼(12)為“誰在線上”按鈕添加BN_CLICKED事件,該事件負(fù)責(zé)將雙擊事件傳
15、來的用戶名加入文本框IDC_SENDNAME中。void CDlgP2P:OnFinduser() / TODO: Add your control notification handler code hereCString strTemp;strTemp=請稍候.;m_FindBtn.SetWindowText(strTemp);m_List.DeleteAllItems(); / 先清空原來顯示的計(jì)算機(jī)名列表GetLanActiveComputer(); / 再次取得局域網(wǎng)中的計(jì)算機(jī)名Sleep(1000); / 程序凍結(jié)1000ms,獲取計(jì)算機(jī)名時(shí)避免其他操作strTemp=誰在線上?(
16、&W);m_FindBtn.SetWindowText(strTemp);(13)為按鈕IDC_SENDBUTTON添加OnSend事件,作用是根據(jù)文本框IDC_SENDNAME傳入的用戶名,選擇服務(wù)端,創(chuàng)建發(fā)送套接字,向指定計(jì)算機(jī)發(fā)送消息。16第二部分 知識點(diǎn)鏈接L8.1 為應(yīng)用系統(tǒng)加入Socket支持L1. SocketSocket的數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket具有一個(gè)類似于文件打開的函數(shù)調(diào)用Socket,該函數(shù)返回一個(gè)整型的Socket描述符,隨后建立連接,數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^該Socket實(shí)現(xiàn)的。Socket分為三類:流式Socket(SO
17、CK_STREAM),數(shù)據(jù)報(bào)Socket(SOCK_DGRAM)及原始Socket(SOCK_RAW)。流式Socket為面向連接,數(shù)據(jù)報(bào)Socket為面向無連接;原始Socket主要用于一些協(xié)議的開發(fā)和測試新的網(wǎng)絡(luò)協(xié)議的實(shí)現(xiàn),可以進(jìn)行比較底層的操作,如IP的直接訪問。Windows Sockets是微軟公司的網(wǎng)絡(luò)程序設(shè)計(jì)接口,它是從BSD UNIX Socket擴(kuò)展而來的。它不僅包含了BSD UNIX Socket風(fēng)格的庫函數(shù),也包含了一組對Windows的擴(kuò)展庫函數(shù),使程序員能夠充分利用Windows的消息驅(qū)動(dòng)機(jī)制進(jìn)行編程。17L8.1 為應(yīng)用系統(tǒng)加入Socket支持L8.2 編寫聊天模塊
18、代碼L1. sockaddr_instruct sockaddr結(jié)構(gòu)為套接字儲存套接字地址信息。語法:struct sockaddr unsigned short sa_family; /* 地址家族, AF_xxx */ char sa_data14; /* 14字節(jié)協(xié)議地址*/ ; 參數(shù)說明:sa_family TCP/IP協(xié)議族默認(rèn)是AF_INET sa_data包含套接字中的目標(biāo)地址和端口信息 為了處理struct sockaddr,使用另一個(gè)類似的結(jié)構(gòu):struct sockaddr_in(in代Internet)。struct sockaddr_in short int sin_f
19、amily; /* 通信類型 */ unsigned short int sin_port; /* 端口 */ struct in_addr sin_addr; /* Internet 地址 */ unsigned char sin_zero8; /* 與sockaddr結(jié)構(gòu)的長度相同*/ ; 18L8.2 編寫聊天模塊代碼L2. gethostname函數(shù)gethostname函數(shù)用以返回本地主機(jī)的標(biāo)準(zhǔn)主機(jī)名。#include / 使用前包含頭文件語法:int PASCAL FAR gethostname(char FAR *name, int namelen);參數(shù)說明:name 一個(gè)指向
20、將要存放主機(jī)名的緩沖區(qū)指針namelen緩沖區(qū)的長度該函數(shù)把本地主機(jī)名存放入由name參數(shù)指定的緩沖區(qū)中。返回的主機(jī)名是一個(gè)以NULL結(jié)束的字符串。主機(jī)名的形式取決于Windows Sockets,它可能是一個(gè)簡單的主機(jī)名,或者是一個(gè)域名。然而,返回的名字必定可以在gethostbyname()和 WSAAsyncGetHostByName()中使用。如果沒有錯(cuò)誤發(fā)生,gethostname()返回0,否則它返回SOCKET_ERROR。應(yīng)用程序可以通過WSAGetLastError()來得到一個(gè)特定的錯(cuò)誤代碼。錯(cuò)誤代碼:WSAEFAULT 名字長度參數(shù)太小WSANOTINTIALISED 在
21、應(yīng)用這個(gè)API前,必須成功地調(diào)用WSAStartup()WSAENTDOWN Windows Sockets實(shí)現(xiàn)檢測到了網(wǎng)絡(luò)子系統(tǒng)的錯(cuò)誤WSAEINPROGRESS 一個(gè)阻塞的Windows Sockets操作正在進(jìn)行19L8.2 編寫聊天模塊代碼L3. 枚舉網(wǎng)絡(luò)資源的函數(shù)1WnetOpenEnum函數(shù)WnetOpenEnum函數(shù)用于啟動(dòng)對網(wǎng)絡(luò)資源進(jìn)行枚舉的過程。語法:DWORD WnetOpenEnum( DWORD dwScope, DWORD dwType, DWORD dwUsage,LPNETRESOURCE lpNetResource, LPHANDLE lphEnum );參數(shù)說
22、明:DwScope表示網(wǎng)絡(luò)枚舉的范圍DwType表示枚舉的資源類型DwUsage表示枚舉資源的用法LpNetResource用于返回網(wǎng)絡(luò)資源信息LphEnum表示枚舉的資源句柄指針20L8.2 編寫聊天模塊代碼2WnetEnumResource函數(shù)WnetEnumResource函數(shù)用于枚舉網(wǎng)絡(luò)資源。語法:DWORD WnetEnumResource( HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize );參數(shù)說明:hEnum由WnetOpenEnum函數(shù)的參數(shù)lphEnum傳入,表示枚舉的資源句柄lpc
23、Count用來決定獲取的資源數(shù)目最大值lpBuffer指向枚舉結(jié)果存放的緩沖區(qū)地址lpBufferSize指向枚舉結(jié)果存儲緩沖區(qū)大小的變量地址 3WnetCloseEnum函數(shù)WnetCloseEnum函數(shù)用于結(jié)束一次枚舉操作。語法:DWORD WnetCloseEnum( HANDLE hEnum );參數(shù)說明:hEnum由WnetOpenEnum函數(shù)的參數(shù)lphEnum傳入21L8.2 編寫聊天模塊代碼L4. gethostbyname函數(shù)gethostbyname函數(shù)能夠通過計(jì)算機(jī)的名稱返回其網(wǎng)絡(luò)信息,這個(gè)信息中包括IP地址。語法:struct hostent FAR * gethost
24、byname ( const char FAR * name );參數(shù)說明:name包含計(jì)算機(jī)名稱的字符串L5. 網(wǎng)絡(luò)字節(jié)順序在Internet上傳輸?shù)臄?shù)據(jù)和本機(jī)內(nèi)存中的數(shù)據(jù)存儲順序不同。網(wǎng)絡(luò)字節(jié)順序NBO(Network Byte Order):按從高到低的順序存儲,在網(wǎng)絡(luò)上使用統(tǒng)一的網(wǎng)絡(luò)字節(jié)順序,可以避免兼容性問題。主機(jī)字節(jié)順序HBO(Host Byte Order):不同的機(jī)器HBO不相同,與CPU設(shè)計(jì)有關(guān)。計(jì)算機(jī)數(shù)據(jù)存儲有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。Internet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序(NBO)在網(wǎng)絡(luò)上傳輸,所以對于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲數(shù)據(jù)的機(jī)器,在In
25、ternet上傳輸數(shù)據(jù)時(shí)就需要進(jìn)行轉(zhuǎn)換。22L8.2 編寫聊天模塊代碼網(wǎng)絡(luò)字節(jié)順序和本機(jī)字節(jié)順序的轉(zhuǎn)換有兩種類型:short(兩個(gè)字節(jié))和long(四個(gè)字節(jié))。這個(gè)函數(shù)對于變量類型unsigned也適用。比如將short從本機(jī)字節(jié)順序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序函數(shù):htons(),意思為“Host to Network Short”。當(dāng)某數(shù)據(jù)必須按照NBO順序,要調(diào)用函數(shù)(例如 htons())來將它從本機(jī)字節(jié)順序(Host Byte Order)轉(zhuǎn)換過來。類似的還有:htons()Host to Network Short htonl() Host to Network Long ntohs()Ne
26、twork to Host Short ntohl()Network to Host Long 需要說明的是,在數(shù)據(jù)結(jié)構(gòu)struct sockaddr_in中,sin_addr和sin_port 需要轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序,而sin_family不需要。原因是sin_addr和sin_port分別封裝在IP和UDP層,因此,它們必須是網(wǎng)絡(luò)字節(jié)順序。但是sin_family域只是被主機(jī)使用來決定在數(shù)據(jù)結(jié)構(gòu)中包含什么類型的地址,所以它必須是本機(jī)字節(jié)順序。同時(shí)sin_family沒有發(fā)送到網(wǎng)絡(luò)上,可以是本機(jī)字節(jié)順序。 23L8.2 編寫聊天模塊代碼L6. IP點(diǎn)數(shù)形式假設(shè)已經(jīng)有一個(gè)sockaddr_in
27、結(jié)構(gòu)體ina,有一個(gè)IP地址“132.241.5.10”需要儲存在其中,就要用函數(shù)inet_addr()將IP地址從點(diǎn)數(shù)格式轉(zhuǎn)換成無符號長整型。使用方法如下: ina.sin_addr.s_addr = inet_addr(132.241.5.10); 注意,inet_addr()返回的地址已經(jīng)是網(wǎng)絡(luò)字節(jié)格式,所以無須再調(diào)用函數(shù)htonl()。當(dāng)inet_addr()發(fā)生錯(cuò)誤時(shí)返回-1。上面的代碼并不完整,編程時(shí)要先進(jìn)行錯(cuò)誤檢查。 還可以將一個(gè)in_addr結(jié)構(gòu)體輸出成點(diǎn)數(shù)格式,要用到inet_ntoa()函數(shù)(“network to ascii”),比如:printf(%s,inet_nto
28、a(ina.sin_addr); 24L8.2 編寫聊天模塊代碼它將輸出IP地址。需要注意的是inet_ntoa()將結(jié)構(gòu)體in_addr作為一個(gè)參數(shù),它返回的是一個(gè)指向一個(gè)字符的指針。它是一個(gè)由inet_ntoa()控制的靜態(tài)指針,所以每次調(diào)用inet_ntoa()時(shí),它就將覆蓋上次調(diào)用時(shí)所得的IP地址。例如:char *a1, *a2; a1 = inet_ntoa(ina1.sin_addr); /* 這是198.92.129.1 */ a2 = inet_ntoa(ina2.sin_addr); /* 這是132.241.5.10 */ printf(address 1: %sn,a1
29、); printf(address 2: %sn,a2); 輸出如下: address 1: 132.241.5.10 address 2: 132.241.5.10 更多信息請參考有關(guān)“網(wǎng)絡(luò)socket編程指南”資料。25L8.2 編寫聊天模塊代碼L7. Sockets編程常用函數(shù)1創(chuàng)建套接字socket函數(shù)SOCKET socket(int af, int type,int protocol);應(yīng)用程序調(diào)用socket函數(shù)來創(chuàng)建一個(gè)能夠進(jìn)行網(wǎng)絡(luò)通信的套接字。第一個(gè)參數(shù)指定應(yīng)用程序使用的通信協(xié)議的協(xié)議族,對于TCP/IP協(xié)議族,該參數(shù)置AF_INET;第二個(gè)參數(shù)指定要?jiǎng)?chuàng)建的套接字類型,流套接
30、字類型為SOCK_STREAM、數(shù)據(jù)報(bào)套接字類型為SOCK_ DGRAM;第三個(gè)參數(shù)指定應(yīng)用程序所使用的通信協(xié)議。該函數(shù)如果調(diào)用成功就返回新創(chuàng)建的套接字的描述符,如果失敗就返回INVALID_ SOCKET。套接字描述符是一個(gè)整數(shù)類型的值。每個(gè)進(jìn)程的進(jìn)程空間里都有一個(gè)套接字描述符表,該表中存放著套接字描述符和套接字?jǐn)?shù)據(jù)結(jié)構(gòu)的對應(yīng)關(guān)系。該表中有一個(gè)字段存放新創(chuàng)建的套接字的描述符,另一個(gè)字段存放套接字?jǐn)?shù)據(jù)結(jié)構(gòu)的地址,因此根據(jù)套接字描述符就可以找到其對應(yīng)的套接字?jǐn)?shù)據(jù)結(jié)構(gòu)。每個(gè)進(jìn)程在自己的進(jìn)程空間里都有一個(gè)套接字描述符表,但是套接字?jǐn)?shù)據(jù)結(jié)構(gòu)都是在操作系統(tǒng)的內(nèi)核緩沖里。26L8.2 編寫聊天模塊代碼2捆
31、綁本地地址bind函數(shù)int bind( SOCKET s, const struct sockaddr FAR *name, int namelen);當(dāng)創(chuàng)建了一個(gè)Socket以后,套接字?jǐn)?shù)據(jù)結(jié)構(gòu)中有一個(gè)默認(rèn)的IP地址和默認(rèn)的端口號。一個(gè)服務(wù)程序必須調(diào)用bind函數(shù)來給其綁定一個(gè)IP地址和一個(gè)特定的端口號。客戶程序一般不必調(diào)用bind函數(shù)來為其Socket綁定IP地址和端口號。該函數(shù)的第一個(gè)參數(shù)指定待綁定的Socket描述符;第二個(gè)參數(shù)指定一個(gè)sockaddr結(jié)構(gòu)。該結(jié)構(gòu)是這樣定義的:struct sockaddr u_short sa_family; char sa_data14;27L8
32、.2 編寫聊天模塊代碼其中:sa_family指定地址族,對于TCP/IP協(xié)議族的套接字,給其置AF_INET。當(dāng)對TCP/IP協(xié)議族的套接字進(jìn)行綁定時(shí),通常使用另一個(gè)地址結(jié)構(gòu)sockaddr_in用來存儲IP地址和端口。struct sockaddr_in short int sin_family;/* Address family */ unsigned short int sin_port;/* Port number */ struct in_addr sin_addr;/* Internet address */ unsigned char sin_zero8;/* Same siz
33、e as struct sockaddr */;sin_family指定協(xié)議族,在socket編程中只能是AF_INETsin_port存儲端口號(使用網(wǎng)絡(luò)字節(jié)順序)sin_addr存儲IP地址,使用in_addr這個(gè)數(shù)據(jù)結(jié)構(gòu)sin_zero僅為了讓sockaddr與sockaddr_in兩個(gè)數(shù)據(jù)結(jié)構(gòu)保持大小相同而保留28L8.2 編寫聊天模塊代碼3建立套接字的連接(1)connect()函數(shù)int connect(SOCKET s,const struct sockaddr FAR *name,int namelen);客戶程序調(diào)用connect函數(shù)來使客戶Socket與監(jiān)聽于name所指定
34、的計(jì)算機(jī)的特定端口上的服務(wù)Socket進(jìn)行連接。如果連接成功,connect返回0;如果失敗則返回SOCKET_ERROR。下面是一個(gè)例子:struct sockaddr_in daddr;memset(void *)&daddr,0,sizeof(daddr);daddr.sin_family=AF_INET;daddr.sin_port=htons(8888);daddr.sin_addr.s_addr=inet_addr(133.197.22.4);connect(ClientSocket,(struct sockaddr *)&daddr,sizeof(daddr);29L8.2 編寫
35、聊天模塊代碼(2)accept()函數(shù)SOCKET accept(SOCKET s,struct sockaddr FAR *addr,int FAR *addrlen);客戶端通過一個(gè)服務(wù)端正在監(jiān)聽(listen())的端口連接(connect())到服務(wù)端,它的連接將加入到等待服務(wù)端接受(accept())的隊(duì)列中。服務(wù)端調(diào)用accept()告訴客戶端有空閑的連接。該函數(shù)將返回一個(gè)新的套接字,這樣就有兩個(gè)套接字了,原來的一個(gè)還在偵聽指定的端口,新的在準(zhǔn)備發(fā)送(send())和接收(recv())數(shù)據(jù)。下面是一個(gè)調(diào)用accept的例子:struct sockaddr_in ServerSoc
36、ketAddr;int addrlen;addrlen=sizeof(ServerSocketAddr);ServerSocket=accept(ListenSocket,(struct sockaddr *)&ServerSocketAddr,&addrlen);30L8.2 編寫聊天模塊代碼4監(jiān)聽連接listen函數(shù)int listen( SOCKET s, int backlog );服務(wù)程序可以調(diào)用listen函數(shù)使其流套接字s處于監(jiān)聽狀態(tài)。處于監(jiān)聽狀態(tài)的流套接字s將維護(hù)一個(gè)客戶連接請求隊(duì)列,該隊(duì)列最多容納backlog個(gè)客戶連接請求。假如該函數(shù)執(zhí)行成功,則返回0;如果執(zhí)行失敗,則返回
37、SOCKET_ERROR。5數(shù)據(jù)發(fā)送send()函數(shù)int send( SOCKET s,const char FAR *buf,int len,int flags );不論是客戶還是服務(wù)器應(yīng)用程序都用send函數(shù)來向TCP連接的另一端發(fā)送數(shù)據(jù)??蛻舫绦蛞话阌胹end函數(shù)向服務(wù)器發(fā)送請求,而服務(wù)器則通常用send函數(shù)來向客戶程序發(fā)送應(yīng)答。第一個(gè)參數(shù)指定發(fā)送端套接字描述符;第二個(gè)參數(shù)指明一個(gè)存放應(yīng)用程序要發(fā)送數(shù)據(jù)的緩沖區(qū);第三個(gè)參數(shù)指明實(shí)際要發(fā)送的數(shù)據(jù)的字節(jié)數(shù);第四個(gè)參數(shù)一般置0。31L8.2 編寫聊天模塊代碼6數(shù)據(jù)接受recv()函數(shù)int recv( SOCKET s, char FAR *
38、buf, int len, int flags );不論是客戶還是服務(wù)器應(yīng)用程序都用recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)。第一個(gè)參數(shù)指定接收端套接字描述符;第二個(gè)參數(shù)指明一個(gè)緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù);第三個(gè)參數(shù)指明buf的長度;第四個(gè)參數(shù)一般置0。當(dāng)應(yīng)用程序調(diào)用recv函數(shù)時(shí),recv先等待s的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢,如果協(xié)議在傳送s的發(fā)送緩沖中的數(shù)據(jù)時(shí)出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤,那么recv函數(shù)返回SOCKET_ERROR,如果s的發(fā)送緩沖中沒有數(shù)據(jù)或者數(shù)據(jù)被協(xié)議成功發(fā)送完畢后,recv先檢查套接字s的接收緩沖區(qū),如果s接收緩沖區(qū)中沒有數(shù)據(jù)或者協(xié)議正在接收數(shù)據(jù),那么re
39、cv就一直等待,直到協(xié)議把數(shù)據(jù)接收完畢。當(dāng)協(xié)議把數(shù)據(jù)接收完畢,recv函數(shù)就把s的接收緩沖中的數(shù)據(jù)拷貝到buf中,recv函數(shù)返回其實(shí)際拷貝的字節(jié)數(shù)。如果recv在拷貝時(shí)出錯(cuò),那么它返回SOCKET_ERROR;如果recv函數(shù)在等待協(xié)議接收數(shù)據(jù)時(shí)網(wǎng)絡(luò)中斷了,那么它返回0。32L8.2 編寫聊天模塊代碼7關(guān)閉套接字closesocket函數(shù)int closesocket(SOCKET s);closesocket函數(shù)用來關(guān)閉一個(gè)描述符為s套接字。由于每個(gè)進(jìn)程中都有一個(gè)套接字描述符表,表中的每個(gè)套接字描述符都對應(yīng)了一個(gè)位于操作系統(tǒng)緩沖區(qū)中的套接字?jǐn)?shù)據(jù)結(jié)構(gòu),因此有可能有幾個(gè)套接字描述符指向同一個(gè)套
40、接字?jǐn)?shù)據(jù)結(jié)構(gòu)。套接字?jǐn)?shù)據(jù)結(jié)構(gòu)中專門有一個(gè)字段存放該結(jié)構(gòu)的被引用次數(shù),即有多少個(gè)套接字描述符指向該結(jié)構(gòu)。當(dāng)調(diào)用closesocket函數(shù)時(shí),操作系統(tǒng)先檢查套接字?jǐn)?shù)據(jù)結(jié)構(gòu)中的該字段的值,如果為1,就表明只有一個(gè)套接字描述符指向它,因此操作系統(tǒng)就先把s在套接字描述符表中對應(yīng)的那條表項(xiàng)清除,并且釋放s對應(yīng)的套接字?jǐn)?shù)據(jù)結(jié)構(gòu);如果該字段大于1,那么操作系統(tǒng)僅僅清除s在套接字描述符表中的對應(yīng)表項(xiàng),并且把s對應(yīng)的套接字?jǐn)?shù)據(jù)結(jié)構(gòu)的引用次數(shù)減1。closesocket函數(shù)如果執(zhí)行成功就返回0,否則返回SOCKET_ERROR。33L8.2 編寫聊天模塊代碼L8. 線程1進(jìn)程和線程一個(gè)進(jìn)程中的所有線程都在該進(jìn)程的虛擬地址空間中,使用該進(jìn)程的全局變量和系統(tǒng)資源。操作系統(tǒng)給每個(gè)線程分配不同的CPU時(shí)間片,在某一個(gè)時(shí)刻,CPU只執(zhí)行一個(gè)時(shí)間片內(nèi)的線程,多個(gè)時(shí)間片中的相應(yīng)
溫馨提示
- 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025屆河北省張家口市高三上學(xué)期期末質(zhì)量檢測地理試題及答案
- 2025年度專業(yè)車庫租賃權(quán)轉(zhuǎn)讓合同
- 2025年度農(nóng)村土地承包經(jīng)營權(quán)流轉(zhuǎn)與農(nóng)業(yè)文化遺產(chǎn)保護(hù)合同
- 2025年度中小企業(yè)流動(dòng)資金授信借款合同
- 2025年度城市河道治理房屋拆遷補(bǔ)償合同
- 2025年度人才共享與借用項(xiàng)目合作協(xié)議
- 2025年度協(xié)商解除勞動(dòng)合同與員工住房安置合同
- 2025年度公司銷售業(yè)務(wù)員協(xié)議書:人工智能賦能下的銷售代理合同
- 2025年度子女對父母贍養(yǎng)及社區(qū)互助保障協(xié)議
- 化妝品店裝修合同
- 人教版四年級數(shù)學(xué)下冊《圖形的運(yùn)動(dòng)(二)》試題(含答案)
- 《老年人權(quán)益保障法》
- 2025年交管12123駕駛證學(xué)法減分題庫與參考答案
- 2025下半年上海事業(yè)單位招考易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 天津市和平區(qū)2024-2025學(xué)年高一(上)期末質(zhì)量調(diào)查物理試卷(含解析)
- 《呼吸》系列油畫創(chuàng)作中詩意建構(gòu)的研究與實(shí)踐
- 客流統(tǒng)計(jì)系統(tǒng)施工方案
- 船舶制造設(shè)施安全生產(chǎn)培訓(xùn)
- 全國駕駛員考試(科目一)考試題庫下載1500道題(中英文對照版本)
- TSG 07-2019電梯安裝修理維護(hù)質(zhì)量保證手冊程序文件制度文件表單一整套
- 設(shè)備損壞評估報(bào)告范文
評論
0/150
提交評論