江南大學TCPIP群聊私聊設(shè)計._第1頁
江南大學TCPIP群聊私聊設(shè)計._第2頁
江南大學TCPIP群聊私聊設(shè)計._第3頁
江南大學TCPIP群聊私聊設(shè)計._第4頁
江南大學TCPIP群聊私聊設(shè)計._第5頁
已閱讀5頁,還剩23頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、TCP/IP網(wǎng)絡(luò)協(xié)議大作業(yè) 題 目: 基于TCP的網(wǎng)絡(luò)通信 班 級: 計科1203班 姓 名: 學 號: 1030412313 摘要本實驗基于TCP/IP協(xié)議實現(xiàn)客戶機/服務(wù)器模式下帶有用戶注冊,登錄驗證功能的互聯(lián)網(wǎng)聊天系統(tǒng)。通過有連接服務(wù)為主體,無連接服務(wù)為輔,實現(xiàn)一對一私聊和多對多群聊。關(guān)鍵詞:TCP/IP UDP Windows Sockets 聊天系統(tǒng) 總體設(shè)計1.1基本協(xié)議的選取TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)協(xié)議屬于傳輸層協(xié)議。其中TCP提供IP環(huán)境下的數(shù)據(jù)可靠傳輸,它提供的服務(wù)包括數(shù)據(jù)流

2、傳送、可靠性、有效流控、全雙工操作和多路復用。通過面向連接、端到端和可靠的數(shù)據(jù)包發(fā)送。通俗說,它是事先為所發(fā)送的數(shù)據(jù)開辟出連接好的通道,然后再進行數(shù)據(jù)發(fā)送;而UDP則不為IP提供可靠性、流控或差錯恢復功能。一般來說,TCP對應(yīng)的是可靠性要求高的應(yīng)用,而UDP對應(yīng)的則是可靠性要求低、傳輸經(jīng)濟的應(yīng)用。本次實驗基于TCP/IP協(xié)議實現(xiàn)基本的聊天功能,包括注冊登錄,群聊及私聊。1.2通訊終端的介紹按類別,將此聊天系統(tǒng)劃分為三大塊,分別為: 本地服務(wù)器: 本地服務(wù)器接收遠程服務(wù)器轉(zhuǎn)發(fā)的消息并顯示消息。 遠程服務(wù)器: 監(jiān)聽客戶端的連接請求; 提供注冊服務(wù),驗證登陸請求; 查看在線人數(shù),發(fā)送在線狀態(tài); 發(fā)送

3、群聊消息及私聊消息。 本地客戶端: 發(fā)送建立TCP連接的請求操作; 發(fā)送注冊信息,登陸消息及退出請求;c) 發(fā)送群聊消息及私聊消息。1.3 程序基本流程 客戶端選擇注冊信息; 客戶端輸入注冊信息; 服務(wù)器接收并處理客戶端注冊信息; 客戶端輸入登錄信息; 服務(wù)器接收并處理登陸信息; 服務(wù)器返回登陸成功與否信息; 若登陸成功,客戶端選擇群聊或私聊; 服務(wù)器根據(jù)客戶端的消息處理群聊或私聊: 若是群聊,則服務(wù)器將此消息群發(fā); 若是私聊,則服務(wù)器將此消息發(fā)送給對應(yīng)用戶;此程序基本通訊流程圖如下:Figure 1-3-1客戶/服務(wù)器程序流程圖1.4面向連接的客戶/服務(wù)器程序的工作流程此程序客戶/服務(wù)器程序

4、的工作流程可大致簡化為一下步驟:a)服務(wù)器先用socket函數(shù)來建立一個套接字,用這個套接字完成通信的監(jiān)聽。b)用bind函數(shù)來綁定一個端口號和IP地址。因為本地計算機可能有多個網(wǎng)址和IP,每一個IP和端口有多個端口。需要指定一個IP和端口進行監(jiān)聽。c)服務(wù)器調(diào)用listen函數(shù),使服務(wù)器的這個端口和IP處于監(jiān)聽狀態(tài),等待客戶機的連接。d)客戶機用socket函數(shù)建立一個套接字,設(shè)定遠程IP和端口。e)客戶機調(diào)用connect函數(shù)連接遠程計算機指定的端口。f)服務(wù)器用accept函數(shù)來接受遠程計算機的連接,建立起與客戶機之間的通信。g)建立連接以后,客戶機用write函數(shù)向socket中寫入數(shù)

5、據(jù)。也可以用read函數(shù)讀取服務(wù)器發(fā)送來的數(shù)據(jù)。h)服務(wù)器用read函數(shù)讀取客戶機發(fā)送來的數(shù)據(jù),也可以用write函數(shù)來發(fā)送數(shù)據(jù)。i)完成通信以后,用close函數(shù)關(guān)閉socket連接。 客戶端程序2.1客戶端運行原理客戶端應(yīng)用程序的工作流程如下: 使用WSAStartup()函數(shù)檢查系統(tǒng)協(xié)議棧的安裝情況。其調(diào)用格式與服務(wù)器端調(diào)用格式類似: WSAStartup(0x0202,&wsaData);WSAStartup(MAKEWORD(2,2),&wsaData); 使用socket()或WSASocket()函數(shù)創(chuàng)建客戶端套接口。其調(diào)用格式同服務(wù)器端調(diào)用格式類似: SOCKE

6、T clientSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 使用connect()或WSAConnect()函數(shù)發(fā)出與服務(wù)器建立連接的請求。常用格式如下:connect(clientSocket,(struct sockaddr*)&serveraddr,sizeof(serveraddr); 連接建立后,使用send()或WSASend()函數(shù)發(fā)送數(shù)據(jù),或使用recv()或WSARecv()函數(shù)接收數(shù)據(jù)。使用closesocket()函數(shù)關(guān)閉套接口。 最后調(diào)用WSACleanup()函數(shù),結(jié)束Windows Sockets API的

7、使用??蛻舳顺绦蛄鞒虉D如下:Figure 2-2-1程序流程圖2.2客戶端程序說明1.客戶端當前用戶結(jié)構(gòu)struct usersint id; /表示第幾個用戶int isOnline; /表示是否在線char username10; /用戶名char passward10; /密碼char ip20;users *next; *user,head,userlogin,*user_online;2.客戶端連接函數(shù)void connect_server(char argv)if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)printf("

8、;Falid to load winsock. n");return;ser_server.sin_family = AF_INET;ser_server.sin_port = htons(iPort);ser_server.sin_addr.s_addr = inet_addr(argv);sClient = socket(AF_INET, SOCK_DGRAM, 0);if (sClient = INVALID_SOCKET)printf("socket() Faild:%dn", WSAGetLastError();return;3.客戶端注冊函數(shù),此函數(shù)為

9、當前用戶輸入注冊信息,并將此信息存儲至user結(jié)構(gòu)體鏈表中。void regist()char username10;char passward10;printf("請輸入注冊用戶名:n");scanf("%s",&username);printf("請輸入注冊密碼:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = inet_ntoa (* (struct in_ad

10、dr *)(*phostinfo->h_addr_list) ); strcpy(user->username,username);strcpy(user->passward,passward);/包含ip信息strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'printf("ip:%sn",user->ip);user->id=i;i = i+1;user->isOnline=0; /表示此用戶已經(jīng)注冊過4.客戶端登陸函數(shù),此函數(shù)為當前用

11、戶輸入登陸信息,并將此信息存儲至userlogin結(jié)構(gòu)體中。/登陸函數(shù)void login()char username10;char passward10;printf("請輸入登陸用戶名:n");scanf("%s",&username);printf("請輸入登陸密碼:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = inet_ntoa (* (struct i

12、n_addr *)(*phostinfo->h_addr_list) ); strcpy(userlogin.username,username);strcpy(userlogin.passward,passward);strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'5.客戶端檢測函數(shù):此函數(shù)檢測客戶端的登陸用戶名和密碼是否正確,通過與服務(wù)器存儲的所有用戶比較得出此用戶的用戶名和密碼是否正確,如果正確,user_state返回2.void check()int i=1;int iSen

13、d_server;int iRec_server;int iLen = sizeof(ser_server);char buf_recv1;user= head.next;iRec_server = recvfrom(sClient,buf_recv,sizeof(buf_recv),0,(struct sockaddr*)&ser_server,&iLen);user_state = (int)buf_recv0;if(user_state =2)printf("登陸成功:n");send();6.客戶端發(fā)送函數(shù):此函數(shù)為客戶端向服務(wù)器發(fā)送注冊和登陸消息,

14、由于發(fā)送的是結(jié)構(gòu)體鏈表,故先將其轉(zhuǎn)換為指針數(shù)組發(fā)送,再由服務(wù)器將其轉(zhuǎn)換為結(jié)構(gòu)體;void send_loginMessage(char argv_server,struct users *usermessage)int buf_len;int pos = 0;int iSend_userMessage;buf_len = sizeof(users);char *buf_send = (char *)malloc(buf_len);memcpy(buf_send,usermessage,buf_len);while(pos<buf_len)iSend_userMessage = sendt

15、o(sClient,buf_send+pos,buf_len,0,(struct sockaddr*)&ser_server,sizeof(ser_server);if(iSend_userMessage=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();break;pos += iSend_userMessage;7. 客戶端發(fā)送群聊消息,通過選擇群聊,服務(wù)器向所有在線人員發(fā)送消息。void send_message(char *argv_local)int i = 1;int iR

16、ecv;int iSend_server;char buf_sDATA_BUFFER;int iLen = sizeof(ser_server);int iLens = sizeof(users);if(user_state =2)while(i != 0)printf("%s:n",user->name);char buf_sendSEND_NAME;scanf("%s", &buf_s);strcat(buf_send, buf_s);iSend_server = sendto(sClient, buf_send, sizeof(buf

17、_send), 0, (struct sockaddr*)&ser_server, iLen);if(iSend_server=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();/發(fā)送IP到服務(wù)器if (stricmp(buf_s, "exit") = 0)break;else if(user_state = 1)printf("用戶登錄失敗,此用戶已經(jīng)登錄.n");else printf("用戶登錄失敗,未注冊或密碼錯誤.n"

18、;);8. 客戶端發(fā)送私聊消息:如果客戶端通過提示選擇私聊,將得到服務(wù)器發(fā)送回的當前在線人員,選擇當前在線人員開啟私聊。void send_message_s(char *argv_local)int i = 1;int iRecv;int pos = 0;int iSend_server;char buf_sDATA_BUFFER;int iLens = sizeof(users);int iLen = sizeof(ser_server);if(user_state =2)while(i != 0)printf("%s:n",user->name);char bu

19、f_sendSEND_NAME = "涂序文:"scanf("%s", &buf_s);strcat(buf_send, buf_s);iSend_server = sendto(sClient, buf_send, sizeof(buf_send), 0, (struct sockaddr*)&ser_server, iLen);if(iSend_server=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();char *buf_rev

20、 = (char *)malloc(iLens);while(pos<iLens)iRecv = recvfrom(sClient,buf_rev+pos,iLens,0,(sockaddr*)&ser_server,&iLen);if(iRecv=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();break;pos += iRecv;user_online = (struct users *)malloc(sizeof(struct users);memcpy(user_onl

21、ine,buf_rev,iLens);printf("%dn",user_online->isOnline);/iRecv = recvfrom(sClient,*name_rev,sizeof(*name_rev),0,(struct sockaddr*)&ser_server,&iLen);if (stricmp(buf_s, "exit") = 0)break;else if(user_state = 1)printf("此用戶已經(jīng)登錄.n");else printf("未注冊或密碼錯誤.n&qu

22、ot;);2.3本地服務(wù)器程序#include<Winsock2.h>#include<stdio.h>#include<stdlib.h>#pragma comment(lib,"ws2_32.lib") #define DEFAULT_PORT 5056void main()int iPort = DEFAULT_PORT;WSADATA WSAData;SOCKET sSocket, sAccept;int iLen;int iSend;char buf1024;char buf_send = "copy"str

23、uct sockaddr_in ser;printf("-n");printf("Server waittingn");printf("-n");if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)printf("Faild to load WinSock.n");return;sSocket = socket(AF_INET, SOCK_DGRAM, 0);if (sSocket = INVALID_SOCKET)printf("socket()Faild

24、:%dn", WSAGetLastError();return;ser.sin_family = AF_INET;ser.sin_port = htons(iPort);ser.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sSocket, (LPSOCKADDR)&ser, sizeof(ser) = SOCKET_ERROR)printf("bind()Faild:%dn", WSAGetLastError();return;iLen = sizeof(ser);memset(buf, 0, sizeof(b

25、uf);while (1)iLen = recvfrom(sSocket, buf, sizeof(buf), 0,(sockaddr*)&ser,&iLen);printf("%sn",&buf);if (stricmp(buf, "exit") = 0)printf("用戶退出,服務(wù)器即將退出.");break;closesocket(sSocket);WSACleanup(); 服務(wù)器程序3.1服務(wù)器運行原理a)使用WSAStartup()函數(shù)檢查系統(tǒng)協(xié)議棧的安裝情況。b)使用socket()或WSASo

26、cket()函數(shù)創(chuàng)建服務(wù)器端通信的套接口。如果套接口創(chuàng)建不成功,也不能執(zhí)行以下的各操作,并且要調(diào)用WSACleanup(),結(jié)束Windows Sockets API的使用。這一步調(diào)用過程確定了相關(guān)五元組的協(xié)議。c)使用bind()函數(shù)將創(chuàng)建的套接口與服務(wù)器地址綁定。它確定了相關(guān)五元組中的本地IP地址和端口號。d)使用listen()函數(shù)使服務(wù)器套接口做好接收連接請求的準備。e)使用accept()或WSAAccept()函數(shù)接收來自客戶端由connect()。f)連接建立連接后,使用send()或WSASend()函數(shù)發(fā)送數(shù)據(jù),或使用recv()或WSARecv()函數(shù)接收數(shù)據(jù)。g)使用cl

27、osesocket()函數(shù)關(guān)閉套接口。h)最后調(diào)用WSACleanup()函數(shù),結(jié)束結(jié)束Windows Sockets API的使用。服務(wù)器運行原理如下:Figure 3-1 服務(wù)器工作流程圖3.2服務(wù)器程序說明1. 服務(wù)器當前用戶結(jié)構(gòu)struct usersint id;int isOnline;char username10;char passward10;char ip20;users *next;*user,login,head,tail,*user_check,login_all10;2. 服務(wù)器連接函數(shù),此函數(shù)將基本連接函數(shù)剝離出來void connect()int iPort =

28、 DEFAULT_PORT;/int yPort = DEFAULT_PORT_1;if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)printf("Faild to load WinSock.n");return;sSocket = socket(AF_INET,SOCK_DGRAM,0);if(sSocket = INVALID_SOCKET)printf("socket() Faild:%dn",WSAGetLastError();return;ser.sin_family = AF_INET;ser.sin

29、_port = htons(iPort);ser.sin_addr.s_addr = htonl(INADDR_ANY);cli.sin_family = AF_INET;cli.sin_port = htons(iPort);if (bind(sSocket, (LPSOCKADDR)&ser, sizeof(ser) = SOCKET_ERROR)printf("bind-()Faild:%dn", WSAGetLastError();return;iLens = sizeof(cli);3.服務(wù)器接收函數(shù),此函數(shù)接收客戶端的注冊信息,并將此信息存儲至user結(jié)

30、構(gòu)體鏈表中。/接收注冊信息void rec_regist()int iLen = sizeof(users);int pos = 0;int iRecv_user;char *buf_rev = (char *)malloc(iLen);user = tail.next;while(pos<iLen)iRecv_user = recvfrom(sSocket,buf_rev+pos,iLen,0,(sockaddr*)&cli,&iLens);if(iRecv_user=SOCKET_ERROR)printf("rec_regist Faild.:%dn&quo

31、t;,WSAGetLastError();break;pos += iRecv_user;memcpy(user,buf_rev,iLen);printf("用戶%s注冊成功.n",user->username);printf("ip:%sn",user->ip);user->isOnline = 0;user->next = (struct users *)malloc(sizeof(struct users);user = user->next;tail.next = user;user->id = 0;4.服務(wù)器

32、接收登陸函數(shù),此函數(shù)為服務(wù)器接收當前用戶輸入登陸信息,并將此信息存儲至userlogin結(jié)構(gòu)體中。/登陸函數(shù)void login()char username10;char passward10;printf("請輸入登陸用戶名:n");scanf("%s",&username);printf("請輸入登陸密碼:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = ine

33、t_ntoa (* (struct in_addr *)(*phostinfo->h_addr_list) ); strcpy(userlogin.username,username);strcpy(userlogin.passward,passward);strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'5.服務(wù)器檢測函數(shù):此函數(shù)檢測客戶端的登陸用戶名和密碼是否正確,通過與本地存儲的所有用戶比較得出此用戶的用戶名和密碼是否正確,如果正確,user_state返回2。如果用戶已登錄,us

34、er->isOnline= 2;如果用戶密碼正確但未登錄,user->isOnline = 1;否則user->isOnline = 0;/檢測函數(shù)void check()int i=1;int iSend_local;int iLen;char buf_send1;user= head.next;while(i=user->id)/輸入的用戶名和密碼正確if(strcmp(login.username,user->username)=0&&strcmp(login.passward,user->passward)=0)/登錄成功并已經(jīng)在線時

35、,不允許登錄if(login.isOnline = user->isOnline)printf("登錄成功.n");user->isOnline = 1;login.isOnline = 2;break;elselogin.isOnline = 1;printf("此用戶已經(jīng)登錄.n");user = user->next;i = i+1;*buf_send = (char)login.isOnline;iSend_local = sendto(sSocket,buf_send,sizeof(buf_send),0,(struct so

36、ckaddr*)&cli,iLens);recv();6.服務(wù)器接收函數(shù):此函數(shù)為服務(wù)器接收到客戶端請求群聊,得到所有在線的人數(shù)并得到其ip,將客戶端需要發(fā)送的消息發(fā)送給各個本地服務(wù)器。/群聊void recv_message()int i = 1;int iRec_local,iSend_local;if(login.isOnline = 2)user = head.next;while(i!=0)char buf_rev1024;iRec_local = recvfrom(sSocket,buf_rev,sizeof(buf_rev),0,(sockaddr*)&cli,&

37、amp;iLens); /放消息,此消息為用戶名字信息if(iRec_local=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();elseprintf("%sn",buf_rev);while(user->id!=0)printf("ip:%sn",user->ip);printf("%d",user->isOnline);if(user->ip!=NULL&&user->isOnline=1)

38、printf("當前在線用戶:%sn",user->username);cli.sin_addr.s_addr = inet_addr(user->ip); /重置客戶端ipiSend_local = sendto(sSocket,buf_rev,sizeof(buf_rev),0,(struct sockaddr*)&cli,iLens);user = user->next;if (stricmp(buf_rev, "exit") = 0)break;else if(login.isOnline= 1)printf("

39、;此用戶已經(jīng)登錄,不可重復登錄.n");else printf("用戶登錄失敗,未注冊或密碼錯誤.n");7. 服務(wù)器接收函數(shù):服務(wù)器接收到私聊請求執(zhí)行此函數(shù),服務(wù)器得到所有在線人數(shù)并將其返回給客戶端,客戶端選擇要私聊的人并由服務(wù)器轉(zhuǎn)發(fā)給其本地服務(wù)器。/私聊void recv_message_s()int pos = 0;int i = 1;int num = 0;int iRec_local,iSend_local;if(login.isOnline = 2)while(i!=0)char buf_rev1024;char buf_revip1024;iRec_

40、local = recvfrom(sSocket,buf_rev,sizeof(buf_rev),0,(sockaddr*)&cli,&iLens); /放消息,此消息為用戶名字信息if(iRec_local=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();elseprintf("%sn",buf_rev);user = head.next;while(user->id!=0)if(user->ip!=NULL&&user->isOnline = 1)printf("當前在線用戶:%

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 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

提交評論