




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、精選優質文檔-傾情為你奉上精選優質文檔-傾情為你奉上專心-專注-專業專心-專注-專業精選優質文檔-傾情為你奉上專心-專注-專業Windows C語言構建網絡聊天室利用C語言編寫Windows應用程序有兩種方式:一種是Windows C編程方式,另一種是Visual C+編程方式。在一般情況下,Visual C+編程方式編寫的程序源代碼量小、開發時的工作量小、工作難度也較小,但編譯后的代碼量較大,運行速度略低;而Windows C編程方式編寫的程序源代碼量雖然較大,但可執行代碼效率高。隨著技術的進步,Visual C+編程方式已被廣泛采用,但象網絡編程等一些對速度要求高、對硬件操作較多的程序,大
2、多數還是用Windows C編程方式開發的。另外,學習Windows C程序設計,還有助于更深入地了解Windows的內幕和Windows API。基本的網絡編程都是建立在Winsock基礎上的。Winsock是90年代初,為了方便網絡編程,由Microsoft聯合了其他幾家公司共同制定的一套WINDOWS下的網絡編程接口,它是通過C語言的動態鏈接庫方式提供給用戶及軟件開發者的,主要由winsock.h頭文件和動態鏈接庫winsock.dll組成,目前有兩個版本:Winsock1.1和Winsock2.0。作為網絡編程接口,Winsock屏蔽了網絡底層的復雜的協議和數據結構,使得編程人員對網絡
3、的操作變得非常簡單,因此,在Win32平臺上,訪問眾多的基層網絡協議,Winsock是首選接口。用Winsock構建一個網絡聊天室,有兩種基本的方式:數據報方式和流方式。面向無連接的數據報方式數據報方式又稱無連接方式,對應的是UDP(User Datagram Protocol)協議。這種方式不提供數據無錯保證,數據可能丟失或重復并且接收順序混亂,后發出的報文可能會先收到,并且報文的長度是有限制的;不過,由于取消了重發校驗機制,能夠達到較高的通信速率,可以用于對數據可靠性要求不高的通信,如實時的語音、圖像傳送和廣播消息等。和C語言一樣,函數是Windows C編程的最基本的單位。不過,Wind
4、ows C主要使用API函數,而網絡編程則主要使用Winsock提供的API函數。數據方式構建網絡聊天室主要使用了以下幾個函數:1WSAStartup():初始化。【函數原型】int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);【使用說明】每一個使用winsock的應用程序,都必須進行WSAStart函數調用,并且只有在調用成功之后才能使用其它的winsock網絡操作函數。返回值:調用成功返回0;否則,返回出錯信息。WversionRequired:表示欲使用的insock版本,這是一個WORD類型的整數,
5、它的高位字節定義的是次版本號,低位字節定義的是主版本號。LpWSAData:是一個指向WSADATA資料的指針。這個資料我們一般不使用。2Socket():創建一個Socket。【函數原型】SOCKET socket(int af,int type,int proctocol);【使用說明】Winsock網絡通信的第一步通常就是調用這個函數。所有的通信在建立之前都有要創建一個Socket。該函數的功能與文件操作中的fopen()類似,返回值是由Winsock定義的一種數據類型SOCKET,它實際是一個整型數據,是Socket創建成功時,Windows分配給程序的Socket編號,后面調用傳輸函
6、數時,可以把它像文件指針樣引用。如果Socket建立失敗,返回值WIVALID_SOCKET。Af:指address family(地址族),一般都填AF_INET,表示是在Internet上的Socket;Type::是Socket的類型,當采用流連接方式時,用SOCK_STREAM;采用數據報文方式時,用SOCK_DGRAM。Proctocol:一般都有為0,表示對兩種類型的Socket分別采用缺省的TCP和UDP傳輸協議。3Bind():為創建Socket指定通信對象。【函數原型】int bind ( SOCKET s, const struct sockaddr FAR* name,
7、int namelen );【使用說明】成功創建了Socket之后,就應該選定通信的對象。首先是自己的程序要與網上的哪臺計算機通話;其次,在多任務的系統下,該臺計算機上可能會有幾個程序在工作,必須指出要與哪個程序通信。前者可以通過IP地址來確定,而后者則由端口號來確定的。一臺計算機有65536個端口,端口號范圍為065535,不同的通信程序使用不同的端口。不過,1024以下的端口號一般都已被一些常用的網絡服務程序所占用,因此,編制自己的通信程序時,指定的端口號應大于1024。s:上一步創建Socket時創建好的套接字。name:是指向描述通信對象地址信息的結構體strict sockaddr_
8、in的指針。namelen:name結構體的長度。Sockaddr_in的定義如下:struct sockaddr_in short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero8;其中,sin_family是指一套地址族,它指定所要使用的通信協議,通常設為AF_INET;sin_port端口號;sin_addr是IP地址;而sin_zero8的作用,只是使該結構的大小和SOCKADDR結構大小相同。IP地址sin_addr結構定義如下:struct in_addr union struc
9、t u_char s_b1,s_b2,s_b3,s_b4; S_un_b; struct u_short s_w1,s_w2; S_un_w; u_long S_addr; S_un;這樣,對于一個IP地址,例如“”,你可以用以下三種方法賦給一個sockaddr結構體(例如struct sockaddr_in m_addr;):方法1:m_addr.sin_addr.S_un.S_un_b.s_b1=192;m_addr.sin_addr.S_un.S_un_b.s_b2=168;m_addr.sin_addr.S_un.S_un_b.s_b3=0;m_addr.sin_addr.S_un.S
10、_un_b.s_b4=1;方法2:m_addr.sin_addr.S_un.S_un_w.s_w1=(1688)|192;m_addr.sin_addr.S_un.S_un_w.s_w2=(18)|0;方法3:m_addr.sin_addr.S_un.S_addr=(124)|(016)|(1688)|192;為了更方便地賦值,winsock還為我們提供了一個函數inet_addr(),可以把用字符串表示的IP地址“”直接賦給結構體m_addr:char * IP_String=”;m_addr.sin_addr.S_un.S_addr=inet_addr(IP_String);4recvfr
11、om()/sendto():【函數原型】int recvfrom ( SOCKET s,char FAR* buf, int len,int flags,struct sockaddr FAR* from, int FAR* fromlen );int sendto (SOCKET s,const char FAR * buf, int len, int flags,const struct sockaddr FAR * to, int tolen);【使用說明】s:是連接用的socket。buf、len:發送或接收的數據包字符串的地址和長度。flags:一般取0。from、fromlen/t
12、o、tolen:含義和用法與bind()中的相同,分別表示接收和發送數據的對象。5Closesocket():【函數原型】int closesocket ( SOCKET s);【使用說明】和關閉文件操作一樣,socketd在使用以后,也要關閉。Internet上的聊天室程序一般都是Client/Server結構的,由服務器提供服務端連接響應,使用者通過客戶端程序登錄到服務器(面向接連的流方式),或直接向服務端發送報文(面向無連接的數據報方式)。相應地,聊天室程序也就分為服務器端和客戶端兩部分。面向無連接的數據報方式的程序流程圖如圖1所示:調用socket()創建一個監聽Socket調用bin
13、d()監聽socket指定通訊對象調用recvfrom()和sendto()進行通訊調用closesocket()關閉socket調用WSAStartup()初化Winsock調用WSAStartup()初化Winsock調用closesocket()關閉socket調用recvfrom()和sendto()進行通訊調用socket()創建一個會話Socket服務器端客戶端 圖1面向無連接的數據報方式流程圖可以為服務器端和客戶端分別建立如圖1、圖2所示對話框: 圖1服務器端 圖2客戶端相應的源程序見附件中的源程序Chat_Room1。二、面向連接的流方式流方式又稱無連接方式,對應的是TCP(T
14、ransport Control Protocol)協議。在這種方式下,兩個通信的應用程序之間先要建立一種連接鏈路,確定了這條鏈路之后,數據才能被正確接收和發送。流方式的特點是通信可靠,對數據有校驗和重發的機制,通常用來做數據文件的傳輸如FTP、Telnet等。這種方式主要使用了以下幾個函數:1Connect():【函數原型】int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen);【使用說明】與通信對象建立連接,主要用在客戶端。其中s、name和namelen的含義與使用方法和bind()相同。如果連接失敗,該
15、函數會返回SOCKET_ERROR。2listen():【函數原型】int listen (SOCKET s,int backlog);【使用說明】對于服務器端程序,當申請到Socket,并指定通信對象為INADDR_ANY之后,就應該等待一個客戶端程序的連接。當沒有連接請求時,就進入等待狀態,直至有一個請求到達為止。其中:s:是socket()創建的socket。backlog:等待連接的隊列長度,可取15。如果當某個客戶程序要求連接之時,服務器已與其他客戶程序連接,則后來的連接請求會被放在隊列中,等待服務器空閑的時候再與之連接。當隊列達到指定長度(backlog的值)時,再來的連接請求都將
16、被拒絕。3accept():【函數原型】SOCKET accept (SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);【使用說明】對與服務器端程序,在接收到一個連接請求之后,要為這個連接建立一個新的socket,這個任務由accept()函數來完成,并把它作為返回值。新建的Socket與原來的Socket有相同的特性,包括端口號。原來的Socket用于繼續等待其他的連接請求,而新生成的Socket才是與客戶端進行通信的實際Socket。一般將參數中的SOCKET稱做“監聽”Socket,它只負責接受連接,不負責通話;而accept返回的
17、SOCKET則稱為“會話”Socket,它只負責與客戶端通話。參數中的指針addr和addrlen用來返回客戶機的sockaddr_in結構體,通過addr可得到客戶機的IP地址和連接端口。使用方法則與bind()中的name和namelen相同。4recv()/send():【函數原型】建立連接后,用來接收和發送數據。其中:s:是連接用的socket。buf、len和flags的含義與作用方法與recvfrom()/connect()中的相同,分別表示接收和發送的數據包字符串的地址、長度和標志。 面向無連接的數據報方式的程序流程圖如圖1所示:調用WSAStartup()初化Winsock調用
18、socket()創建一個監聽Socket調用bind()為監聽Socket指定通訊對象調用listen()設置等待連接狀態調用accept()接收連接并生成會話socket調用send()和recv()進行對話調用closesocket()關閉socket調用WSAStartup()初化Winsock調用socket()創建一個會話Socket調用connect()與服務器端連接調用send()和recv()進行對話調用closesocket()關閉socket阻塞,等待用戶連接阻塞,等待用戶發送數據服務器端客戶端圖2面向連接的流方式流程圖分別為服務器端和客戶端建立如圖3、圖4所示對話框: 圖
19、3 圖4這是一個單方向傳送的面向連接的的流方式聊天程序,源程序附在附件源程序Chat_Room2中,源代碼比較簡單,就不在這里另作說明了。三、面向連接的異步模式在上面的流方式中,函數listen()要等到有客房端的連接請求或是出錯時才能返回;recv()函數也要等到有數據發送過來的時候或是出錯的時候才能返回。這時,如果網絡擁擠或一次發送的數據量過大,交換的數據不能在短時間內傳送完, 收發數據的函數就因此不能返回,我們把這種現象叫做阻塞。在阻塞期間,除了等待網絡操作完成不能進行任何操作。為了解決這一問題,Winsock為我們提供了一種異步模式,在這種模式中,函數在被調用后立即返回,Winsock
20、通過函數WSAAsyncSelect()來實現非阻塞通信。方法是,由該函數指定某種網絡事件(如有數據到達、可以發送數據、有程序請求連接等),當被子指定的網絡事件發生時,由Winsock發送由程序事先約定的消息。程序中就可以根據這些消息做出相應的處理。WSAAsyncSelect(),它的原型是:int WSAAsyncSelect (SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);Socket在這個函數調用中被自動設成非阻塞方式,hWnd是接收Winsock消息的窗口句柄,wMsg是向窗口發出的消息名稱,用戶可以任意定義。LEvent是被指定
21、的網絡事件,如下表所示:網絡事件lEvent值說明FD_READ希望Socket收到數據時發送讀的消息FD_WRITE希望Socket發送數據時發送寫的消息FD_OOB希望OOB data到達時發送到達的消息FD_ACCEPT希望有連接到來時發送連接請求的消息FD_CONNECT希望完成連接時發送連接完成的消息FD_CLOSE希望接收Socket關閉的消息FD_QOS希望接收Socket服務質量(QoS)變化的消息FD_GROUP_QOS希望接收Socket服務質量(QoS)不變的消息FD_ROUTING_INTERFACE_CHANGE希望接收指定的地址路由接口變化的消息FD_ADDRESS
22、_LIST_CHANGE希望接收Socket協議族局部地址變化的消息需要注意的是,WSAAsyncSelect()的設定是針對某一個Socket的,也就是說,只有當被設定為異步模式的Socket事件發生時,才會發送這些信息。如果開啟了很多Socket,而要讓每個Socket都變成異步模式,那么就必須對每一個Socket都呼叫WSAAsyncSelect()來一一設定。有了異步模式之后,可建立如下的服務器端和客戶端程序,對話框如圖5、圖6所示: 服務器端和客戶端程序分別為:Chat_RoomS.h#defineSER_MESSAGEWM_USER+100#define MaxNumber 5in
23、tWSA_return;WSADATAWSAData;SOCKETserver_hSocket;SOCKETListen_hSocket;struct sockaddr_inserver_addr;struct sockaddr_inListen_addr;int Listen_addrlen=sizeof(Listen_addr);intfromlen=sizeof(server_addr);BOOLserver_bErr;UINT server_uPort;char ShowText1024;charInputText256;charReceive_Text256;SOCKETnSocke
24、tMaxNumber;char*ClientIPMaxNumber;inti;charComeMsg30= 走進聊天室rn;charLeaveMsg30= 離開聊天室rn;charLeaveMsg130= 異常離開rn;BOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);Chat_RoomS.c#include#includeresource.h#includeChat_RoomS.hint APIENTRY WinMain(HINSTANCE hInstance,HINSTAN
25、CE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)DialogBox(hInstance,(LPCTSTR)DIALOG1,NULL,(DLGPROC)Hostname_ipDlgPro);return(TRUE);BOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)switch(message)case WM_INITDIALOG:WSA_return=WSAStartup(0 x0002,&WSAData);if(WSA_return
26、!=0)MessageBox(NULL,初始化失敗!,警告!,MB_OK);WSACleanup();return TRUE;case SER_MESSAGE:switch(lParam)case FD_ACCEPT:Listen_hSocket=accept(server_hSocket,(LPSOCKADDR)&Listen_addr,&Listen_addrlen);for(i=0;i0)MessageBox(NULL,異步模式創建失敗!,警告!,MB_OK);ClientIPi=inet_ntoa(Listen_addr.sin_addr);break;if(iMaxNumber)st
27、rcat(ShowText,ClientIPi);strcat(ShowText,ComeMsg);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);for(i=0;iMaxNumber;i+)if(nSocketi!=0)send(nSocketi,ClientIPi,strlen(ClientIPi),0);send(nSocketi,ComeMsg,strlen(ComeMsg),0);return TRUE;case FD_READ:for(i=0;iMaxNumber;i+)if(nSocketi=wParam)recv(nSocketi,Rece
28、ive_Text,256,0);strcat(ShowText,ClientIPi);strcat(ShowText,:rn );strcat(ShowText,Receive_Text);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);for(i=0;iMaxNumber;i+)if(nSocketi!=0)send(nSocketi,ClientIPi,strlen(ClientIPi),0);send(nSocketi,:rn ,strlen(:rn ),0);send(nSocketi,Receive_Text,strlen(Receive_Tex
29、t),0);return TRUE;case FD_WRITE:return TRUE;case FD_CLOSE:for(i=0;iMaxNumber;i+)if(nSocketi=wParam)strcat(ShowText,ClientIPi);strcat(ShowText,LeaveMsg);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);closesocket(nSocketi);nSocketi=0;for(i=0;iMaxNumber;i+)if(nSocketi!=0)send(nSocketi,ClientIPi,strlen(Clie
30、ntIPi),0);send(nSocketi,LeaveMsg,strlen(LeaveMsg),0);return TRUE;default:for(i=0;iMaxNumber;i+)if(nSocketi=wParam)strcat(ShowText,ClientIPi);strcat(ShowText,LeaveMsg1);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);closesocket(nSocketi);nSocketi=0;for(i=0;i0)MessageBox(NULL,異步模式創建失敗!,警告!,MB_OK);break;se
31、rver_addr.sin_family=AF_INET;server_addr.sin_addr.S_un.S_addr=INADDR_ANY;server_uPort=GetDlgItemInt(hDlg,IDC_PORTUINT,&server_bErr,TRUE);server_addr.sin_port=htons(u_short)server_uPort);if(bind(server_hSocket,(LPSOCKADDR)&server_addr,sizeof(server_addr)=SOCKET_ERROR)MessageBox(NULL,綁定端口失敗!,警告,MB_OK)
32、;break;if(listen(server_hSocket,5)=SOCKET_ERROR)MessageBox(NULL,偵聽失敗!,警告!,MB_OK);break;strcpy(ShowText,服務器建立成功!rn);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);return TRUE;case IDC_SHOWTEXT:if(HIWORD(wParam)=EN_CHANGE)if(strlen(ShowText)1024-256)strcpy(ShowText,);case IDC_INPUTTEXT:if(HIWORD(wParam)=E
33、N_CHANGE)GetDlgItemText(hDlg,IDC_INPUTTEXT,InputText,256);if(InputTextstrlen(InputText)-1=n)strcat(ShowText,管理員:rn );strcat(ShowText,InputText);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);for(i=0;iMaxNumber;i+)if(nSocketi!=0)send(nSocketi,管理員:rn ,strlen(管理員:rn ),0);send(nSocketi,InputText,strlen(Inpu
34、tText),0);strcpy(InputText,);SetDlgItemText(hDlg,IDC_INPUTTEXT,InputText);return TRUE;case IDCANCEL:WSAAsyncSelect(server_hSocket,hDlg,0,0);closesocket(server_hSocket);WSACleanup();EndDialog(hDlg,TRUE);return TRUE;return FALSE;Chat_RoomC.h#define CLI_MESSAGE WM_USER+200intlen;intWSA_return;WSADATAWS
35、AData;SOCKETclient_hSocket;struct sockaddr_inclient_addr;BOOLbErr;UINT client_uPort;char ClientIP20;char InputText256;charReceiveText256;charShowText1024;BOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);Chat_RoomC.c#include#includeresource.h#includeChat_RoomC.hint
36、APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)DialogBox(hInstance,(LPCTSTR)DIALOG1,NULL,(DLGPROC)Hostname_ipDlgPro);return(TRUE);BOOL APIENTRY Hostname_ipDlgPro(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)switch(message)case WM_INITDIALOG:WSA_retur
37、n=WSAStartup(0 x0002,&WSAData);if(WSA_return!=0)MessageBox(NULL,初始化失敗!,警告!,MB_OK);WSACleanup();return TRUE;case CLI_MESSAGE:switch(lParam)case FD_READ:len=recv(client_hSocket,ReceiveText,256,0);ReceiveTextlen=0;strcat(ShowText,ReceiveText);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);return TRUE;case
38、FD_WRITE:return TRUE;case FD_CLOSE:return TRUE;case FD_CONNECT:return TRUE;default:strcat(ShowText,網絡錯誤,連接失敗!);SetDlgItemText(hDlg,IDC_SHOWTEXT,ShowText);closesocket(client_hSocket);return TRUE;case WM_COMMAND:switch(LOWORD(wParam)case IDC_IPADDRESS:if(HIWORD(wParam)=EN_CHANGE)GetDlgItemText(hDlg,IDC_IPADDRESS,ClientIP,20);break;case IDC_INPUTTEXT:if(HIWORD(wParam)=EN_CHANGE)GetDlgItemText(hDlg,IDC_INPUTTEXT,InputText,256);if(InputTextstrlen(InputText)-1=n)send(client_hSocket,InputText,256,0);strcpy(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 充分準備的行政組織理論試題及答案
- 西藥批發企業客戶關系管理策略與實施考核試卷
- 嵌入式開發考試案例解析試題及答案
- 行政組織理論的實踐性分析與2025年試題及答案
- 四級軟件測試職業生涯規劃試題及答案
- 軟件測試工程師考試常見問題試題及答案
- 嵌入式系統的故障排除指南試題及答案
- 疾病預防控制檢測考核試卷
- 油品質量分析與檢測技術考核試卷
- 開發中的最佳實踐試題及答案
- 民用爆炸物品倉庫管理規定培訓課件
- 10篇說明文閱讀題及答案
- 項目式學習的探索
- (完整版)【鋼琴譜】大魚鋼琴譜
- 藥品從輕處罰申請書范本
- 工藝品軟裝施工方案
- 二手車鑒定及評估教案
- 【培養】(完整版)師帶徒培養方案
- 一文讀懂-特魯索綜合征病例、影像、診斷、治療
- 體育旅游課件第二章體育旅游資源
- 2023年科技特長生招生考試試卷
評論
0/150
提交評論