




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、摘要摘要26目錄目錄1總體設計41.1基本協議的選取41.2通信終端介紹41.3面向連接的客戶端/服務器程序工作流程52用戶端設計62.1客戶端設計62.2服務器端設計113服務器端設計144運行結果244.1總服務器端244.2客戶端1254.3客戶端225總體設計1總體設計1.1基本協議的選取TCP和UDP協議屬于傳輸層協議,本實驗選擇的協議是TCP協議。UDP是面向無連接的通訊協議,UDP數據包括目的端口號和源端口號信息,由于通訊不需要連接,所以可以實現廣播發送。UDP通訊時不需要接收方確認,屬于不可靠的傳輸,可能會出現丟包現象,實際應用中要求程序員編程驗證。UDP與TCP位于同一層,但
2、它不管數據包的順序、錯誤或重發。欺騙UDP包比欺騙TCP包更容易,因為UDP沒有建立初始化連接(也可以稱為握手)(因為在兩個系統間沒有虛電路),也就是說,與UDP相關的服務面臨著更大的危險。TCP是面向連接的通信協議,通過三次握手建立連接,通訊完成時要拆除連接,由于TCP是面向連接的所以只能用于端到端的通訊。TCP提供的是一種可靠的數據流服務,采用“帶重傳的肯定確認”技術來實現傳輸的可靠性。TCP還采用一種稱為“滑動窗口”的方式進行流量控制,所謂窗口實際表示接收能力,用以限制發送方的發送速度。如果IP數據包中有已經封好的TCP數據包,那么IP將把它們向上傳送到TCP層。TCP將包排序并進行錯誤
3、檢查,同時實現虛電路間的連接。TCP數據包中包括序號和確認,所以未按照順序收到的包可以被排序,而損壞的包可以被重傳。TCP將它的信息送到更高層的應用程序,例如Telnet的服務程序和客戶程序。應用程序輪流將信息送回TCP層,TCP層便將它們向下傳送到IP層,設備驅動程序和物理介質,最后到接收方。所以使用面向連接的服務可以保證通信的可信度。本次實驗基于TCP/IP協議實現基本的聊天功能,包括注冊登錄,群聊及私聊。1.2通信終端介紹本聊天系統共分為三塊:Ø 總服務器l 監聽客戶端的連接請求l 提供注冊服務,驗證登錄請求l 發送在線狀態l 發送群聊、私聊消息Ø 本地客戶端l 發送
4、建立TCP連接請求操作l 發送注冊、登錄信息、退出請求l 發送群聊、私聊消息Ø 本地服務器l 用于接收總服務器端轉發的消息并顯示消息1.3面向連接的客戶端/服務器程序工作流程此程序客戶/服務器程序的工作流程可大致簡化為一下步驟: a) 服務器先用socket函數來建立一個套接字,用這個套接字完成通信的監聽。 b) 用bind函數來綁定一個端口號和IP地址。因為本地計算機可能有多個網址和IP,每一個IP和端口有多個端口。需要指定一個IP和端口進行監聽。 c) 服務器調用listen函數,使服務器的這個端口和IP處于監聽狀態,等
5、待客戶機的連接。 d) 客戶機用socket函數建立一個套接字,設定遠程IP和端口。 e) 客戶機調用connect函數連接遠程計算機指定的端口。 f) 服務器用accept函數來接受遠程計算機的連接,建立起與客戶機之間的通信。 g) 建立連接以后,客戶機用write函數向socket中寫入數據。也可以用read函數讀取服務器發送來的數據。 h) 服務器用read函數讀取客戶機發送來的數據,也可以用write函數來發送數據。 i) 完成通信以后,用close函數關閉socke
6、t連接。 用戶端設計2用戶端設計2.1客戶端設計#include<Winsock2.h>#include<iostream>#include<string>using namespace std;#pragma comment(lib,"WS2_32")#define iport 5050#define DATA_BUFFER 1024SOCKET sClient;struct sockaddr_in ser;char nickname20; /昵稱char password20; /密碼char isend_buf1024;c
7、har send_buf1024;char recv_buf1024;char user2020; /在線的人員int size=0; /在線的人數void log_register();void show_user()cout<<endl<<endl;cout<<"當前在線的人如下:"<<endl;cout<<endl;cout<<"*"<<endl;for(int i=0;i<size;i+)cout<<"* "<<i
8、+1<<": "<<useri;if(strcmp(useri,nickname)=0)cout<<"(本人)"<<endl;elsecout<<endl;cout<<"*"<<endl;void get_user(char *c) /獲得所有在線的人員int i=0;int temp=0;while(i<strlen(c)while(ci!='40'&&i<strlen(c)i+;strncpy(users
9、ize,c+temp,i);usersizei-temp='0'size+;i+;temp=i;void private_group()cout<<"*"<<endl;cout<<"* 1、私聊 2、群聊 3、退出 *"<<endl;cout<<"*"<<endl;show_user(); /顯示在線人員cout<<endl;int choice;cout<<"輸入你的選擇:"cin>>cho
10、ice;if (cin.fail()|(choice<1|choice>3)cin.clear();getchar();cout<<endl<<"輸入的選擇有誤,請重新選擇!"<<endl<<endl;system("pause");system("cls");private_group();if(choice=3)char infom50;strcpy(infom,"#$#");strcat(infom,nickname);strcat(infom,&q
11、uot;已下線!");send(sClient, infom, strlen(infom), 0);cout<<endl;system("pause");system("cls");log_register();if(choice=1)cout<<endl<<"你選擇的私聊對象(編號):"int p;cin>>p;char send_buf20;strcpy(send_buf,"#$prn");strcat(send_buf,userp-1);strcat(
12、send_buf," ");send(sClient, send_buf, strlen(send_buf), 0);recv(sClient, recv_buf, 1023, 0);if(strcmp(recv_buf,"現在可以發送私聊信息!")=0)cout<<endl;cout<<"*"<<endl;cout<<"* 當前為私聊模式! *"<<endl;cout<<"*"<<endl<<end
13、l;elsecout<<endl<<"你選擇的私聊對象已下線!"<<endl<<endl;system("pause");system("cls");private_group();if(choice=2)cout<<endl;cout<<"*"<<endl;cout<<"* 當前為群聊模式! *"<<endl;cout<<"*"<<endl&l
14、t;<endl;void log_register()cout<<"*"<<endl;cout<<"* 1、登錄 2、注冊 3、退出 *"<<endl;cout<<"*"<<endl;int choice;cout<<"輸入你的選擇:"cin>>choice;if (cin.fail()|(choice<1|choice>3)cin.clear();getchar();cout<<endl&
15、lt;<"輸入的選擇有誤,請重新選擇!"<<endl<<endl;system("pause");system("cls");log_register();if(choice=3)cout<<endl;system("pause");exit(0);cout<<endl<<endl;cout<<"*"<<endl;cout<<"* 昵稱:"cin>>nicknam
16、e;cout<<"* 密碼:"cin>>password;cout<<"*"<<endl;char info50="昵稱:" strcat(info,nickname);strcat(info," 密碼:");strcat(info,password);char r_info50;/連接服務器sClient=socket(AF_INET,SOCK_STREAM,0);connect(sClient,(struct sockaddr*)&ser,sizeof(s
17、er);if(choice=1)strcpy(r_info,"#");strcat(r_info,info);send(sClient,r_info,strlen(r_info),0);recv(sClient,recv_buf,1023,0);int flag=0;if(strcmp(recv_buf,"請先注冊!")=0)cout<<endl<<"登錄失敗,請先注冊!"<<endl<<endl;flag=1;if(strcmp(recv_buf,"密碼輸入有誤!"
18、)=0)cout<<endl<<"密碼輸入有誤,請重新登錄!"<<endl<<endl;flag=1;if(strcmp(recv_buf,"該用戶已登錄,不可重復登錄!")=0)cout<<endl<<recv_buf<<endl<<endl;flag=1;if(strncmp(recv_buf,"成功登陸",8)=0)cout<<endl<<"登錄成功,可以參與聊天!"<<endl
19、<<endl;size=0;get_user(recv_buf+8);system("pause");system("cls");private_group();if(flag=1) /密碼輸入有誤,請重新登錄!cout<<endl;system("pause");system("cls");log_register();if(choice=2)strcpy(r_info,"$");strcat(r_info,info);send(sClient, r_info, siz
20、eof(r_info), 0);recv(sClient, recv_buf,1023, 0);if(strncmp(recv_buf,"注冊成功!",10)=0)cout<<endl<<"注冊成功,可以參與聊天!"<<endl<<endl;size=0;get_user(recv_buf+10);system("pause");system("cls");private_group();if(strcmp(recv_buf,"該用戶已注冊,請直接登錄!&q
21、uot;)=0)cout<<endl<<recv_buf<<endl<<endl;void connect_chat(char ip20)WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)cout<<"Failed to load winSock."<<endl;return;/填寫要連接的服務器地址信息ser.sin_family=AF_INET;ser.sin_port=htons(iport);ser.sin_addr.s_a
22、ddr=inet_addr(ip);/建立客戶端流式套接口sClient=socket(AF_INET,SOCK_STREAM,0);if(sClient=INVALID_SOCKET)cout<<"socker()Failed:"<<WSAGetLastError<<endl;return;cout<<endl;log_register();char name420;while(1)for(int i=0;i<4;i+)strcpy(namei,nickname);cout<<nickname<<
23、;":"cin>>send_buf;strcpy(isend_buf,strcat(name0,":");strcat(isend_buf,send_buf);if(strcmp(send_buf,"quit")=0)strcpy(isend_buf,strcat(name1,"已下線!");send(sClient,isend_buf,strlen(isend_buf),0);if(strcmp(send_buf,"quit")=0)cout<<endl;char te
24、mp50="0"recv(sClient,temp,49,0);size=0;get_user(temp);cout<<endl;system("pause");system("cls");private_group();closesocket(sClient);WSACleanup();system("pause");void main()cout<<"請輸入對方的IP地址:"char ip20;cin>>ip;connect_chat(ip);2.2服務器
25、端設計#include<iostream>#include<winsock2.h>#include<list>using namespace std;#pragma comment(lib,"WS2_32")#define iport 5050void main()cout<<"-"<<endl;cout<<"Server waiting"<<endl;cout<<"-"<<endl;WSADATA wsaD
26、ata;if(WSAStartup(MAKEWORD(2,2),&wsaData)cout<<"加載winsock失敗!"<<endl;return ;/建立服務器端監聽套接口SOCKET slisten,sAccept;slisten=socket(AF_INET,SOCK_STREAM, 0); if(slisten=INVALID_SOCKET)cout<<"創建socket失敗!"<<endl;return ;/初始化監聽套接口地址信息sockaddr_in ser;ser.sin_fami
27、ly=AF_INET;ser.sin_port=htons(iport);ser.sin_addr.s_addr=INADDR_ANY;/綁定套接口到本地if(bind(slisten,(sockaddr*)&ser, sizeof(sockaddr_in)=SOCKET_ERROR)cout<<"綁定失敗!"<<endl;return ;/ 使用監聽套接字進行監聽 int iRet = listen(slisten, FD_SETSIZE); /將套接口設置為非阻塞狀態unsigned long ulEnable=1;iRet=ioctls
28、ocket(slisten,FIONBIO,&ulEnable);if(iRet=SOCKET_ERROR)cout<<"設置非阻塞態失敗!"<<endl;return;fd_set fsListen; /fd_set為套字集合FD_ZERO(&fsListen); /FD_ZERO(*set)將集合set清空 fd_set fsRead; FD_ZERO(&fsRead); timeval tv;tv.tv_sec=1;tv.tv_usec=0;list<SOCKET> ls;int flag=0;while(1
29、)/ 接收來自客戶端的連接FD_SET(slisten, &fsListen);/FD_SET(s, *set)將套接字s加入到集合set中iRet=select(1, &fsListen, NULL, NULL, &tv); if(iRet > 0) sockaddr_in cli; int iLen = sizeof(sockaddr_in); sAccept=accept(slisten, (sockaddr*)&cli,&iLen);flag=1;ls.push_back(sAccept);if(sAccept=INVALID_SOCKET
30、)cout<<"接收失敗!"<<endl;exit(0);FD_ZERO(&fsRead); if(flag=1)FD_SET(sAccept, &fsRead); / 檢測集合中的套接字是否有數據可讀 iRet = select(1, &fsRead, NULL, NULL, &tv); if(iRet>0)char recv_buf1024="0"int iRecv=recv(sAccept,recv_buf,1023,0);cout<<recv_buf<<endl
31、;3服務器端設計#include<iostream>#include<winsock2.h>#include<sstream>#include<list>#include<fstream>#include<string>#include<map>using namespace std;#pragma comment(lib,"WS2_32")#define iport 5050stringstream ss;SOCKET slisten,sAccept;sockaddr_in ser;cha
32、r user2020; /在線用戶int size=0;map<string,string> name_ip;map<string,string> ip_name;map<SOCKET,string> socket_ip;map<string,SOCKET> ip_socket;map<string,bool> online; /用戶是否在線map<string,int> ip_kind; /1表示私聊,2表示群聊map<string,string> ip_ip; /兩個私聊對象的iptemplate <
33、typename out_type,typename in_type>void convert(in_type in,out_type &out)ss<<in;ss>>out;ss.clear();string input_to_file(char *c)fstream dataFile; /定義文件操作對象int i = 0;while (ci != '40')i+;dataFile.open("info.txt", ios:out|ios:app); /創建一個文件if (!dataFile) /檢查文件是否創建成功
34、cout << "error open" << endl;return ""dataFile << c << "n" / 向文件寫入數據dataFile.close();char NAME10;strncpy(NAME, c + 5, i - 5);NAMEi - 5 = '0'string temp = NAME;return temp + "已注冊本服務器"string search_file(char* c,int flag)ifstream d
35、ataFile("info.txt"); /定義文件操作對象string buffer;char name20;char password20;stringstream ss;char info_name20;int i = 0;while (ci != '40')i+;strncpy(info_name, c, i);info_namei = '0'char NAME10;strncpy(NAME, info_name + 5, strlen(info_name) - 5);NAMEstrlen(info_name) - 5 = '
36、0'string name_temp = NAME;while (getline(dataFile, buffer)ss.clear();ss.str(buffer);ss >> name >> password;if(strcmp(info_name, name) = 0 &&flag=0)return "該賬戶已注冊過!"if (strcmp(info_name, name) = 0 && buffer = c)return name_temp + "已上線!"if (strcmp(in
37、fo_name, name) = 0 && buffer != c)return "密碼輸入有誤!"dataFile.close();return "該用戶不存在!"char* getname(char* c)char name20;int i = 0;while (ci != '40')i+;strncpy(name, c, i);namei = '0'return name;void new_connect(string ip,char* recv_buf)sockaddr_in sa;char IP2
38、0;convert(ip,IP);if(ip_socketip=INVALID_SOCKET|ip_socketip=SOCKET_ERROR|ip_socketip=NULL)SOCKET st=socket(AF_INET,SOCK_STREAM, 0); sa.sin_family=AF_INET;sa.sin_port=htons(iport);sa.sin_addr.s_addr=inet_addr(IP);if(connect(st,(sockaddr*)&sa,sizeof(sockaddr)=INVALID_SOCKET)cout<<"連接失敗!&
39、quot;<<endl;ip_socketip=st;send(st, recv_buf, strlen(recv_buf), 0); elsesend(ip_socketip, recv_buf, strlen(recv_buf), 0);void delete_user(char* name)int loc=-3;for(int i=0;i<size;i+)if(strcmp(name,useri)=0)loc=i;onlinename=0;break;if(loc!=-3)for(int i=0;i<size&&size>1;i+)strcp
40、y(useri,useri+1);size-;char* quit_mode(char* recv_buf,string ip,int mode,SOCKET sock)char user_online50;strcpy(user_online,"");for(int i=0;i<size;i+)strcat(user_online,useri);if(i!=size-1)strcat(user_online," ");int length=strlen(recv_buf);if(length>8)char temp10;char offli
41、ne_user20;strncpy(offline_user,recv_buf,length-7);offline_userlength-7='0'strncpy(temp,recv_buf+length-7,7);temp7='0'if (strcmp(temp, "已下線!") = 0) send(sock,user_online,strlen(user_online),0);cout<<user_online<<"hai"<<endl;ip_kindip=0;if(mode=0)s
42、trcat(offline_user,"已退出群聊!");else if(mode=1)strcat(offline_user,"已退出私聊!");return offline_user;elsereturn "#"elsereturn "#"void handler(char* recv_buf,SOCKET &sock,list<string> &ls,string ip)char info10;strncpy(info, recv_buf, 5);info5 = '0
43、9;char user_name20;if (strcmp(info, "$昵稱") = 0) /注冊strcpy(user_name,getname(recv_buf+6);string temp = search_file(recv_buf+1,0);if (temp = "該賬戶已注冊過!")send(sock, "該賬戶已注冊過!", 16, 0);new_connect(ip,"該賬戶已注冊過!");elsestring tip = input_to_file(recv_buf+1);cout <&
44、lt; tip << endl;strcpy(usersize,user_name);size+;ip_nameip=user_name;name_ipuser_name=ip;ip_kindip=2; /群聊onlineuser_name=1;char register_user50="注冊成功!"for(int i=0;i<size;i+)strcat(register_user,useri);if(i!=size-1)strcat(register_user," ");send(sock, register_user, strle
45、n(register_user), 0);new_connect(ip,"注冊成功!");else if (strcmp(info, "#昵稱") = 0) /登錄strcpy(user_name,getname(recv_buf+6);string temp = search_file(recv_buf+1,1);if (temp = "密碼輸入有誤!")send(sock, "密碼輸入有誤!", sizeof(temp), 0);new_connect(ip,"密碼輸入有誤!");else
46、if (temp = "該用戶不存在!")send(sock, "請先注冊!", sizeof(temp), 0);new_connect(ip,"請先注冊!");cout << "一用戶嘗試連入,但不存在該用戶!" << endl;elsestrcpy(usersize,user_name);size+;ip_nameip=user_name;name_ipuser_name=ip;ip_kindip=2; /群聊onlineuser_name=1;char register_user50
47、="成功登陸"for(int i=0;i<size;i+)strcat(register_user,useri);if(i!=size-1)strcat(register_user," ");send(sock, register_user, strlen(register_user), 0);new_connect(ip,"成功登陸");cout << temp << endl;else if (strcmp(info, "#$prn") = 0)strcpy(user_name,g
48、etname(recv_buf+5);if(onlineuser_name) /選擇私聊的對象在線send(sock, "現在可以發送私聊信息!", 40, 0);ip_kindip=1;ip_ipip=name_ipuser_name;elsesend(sock, "你選擇的私聊對象已下線!", 40, 0);else if (strcmp(info, "#$#") = 0) cout << recv_buf+5 << endl;strncpy(user_name,recv_buf+5,strlen(recv
49、_buf)-12);char i_t20;convert(ip,i_t);strcat(ip_t,i_t);*/ip_socketip=INVALID_SOCKET;user_namestrlen(recv_buf)-12='0'for(list<string>:iterator ite=ls.begin();ite!=ls.end();ite+)new_connect(*ite,recv_buf);ls.remove(ip);closesocket(sock);sock=INVALID_SOCKET;delete_user(user_name);elseif(ip
50、_kindip=1) /私聊char s_name20;string friend_ip=ip_ipip;convert(ip_namefriend_ip,s_name);char feedback50;strcpy(feedback,quit_mode(recv_buf,ip,1,sock);if(strcmp(feedback,"#")=1)strcpy(recv_buf,feedback);elsestrcat(recv_buf," (私聊");strcat(recv_buf,s_name);strcat(recv_buf,")"
51、;);cout << recv_buf << endl;char IP20;convert(friend_ip,IP);new_connect(ip,recv_buf);if(onlineip_namefriend_ip=1)new_connect(IP,recv_buf);elsechar feedback50;strcpy(feedback,quit_mode(recv_buf,ip,0,sock);if(strcmp(feedback,"#")=1)strcpy(recv_buf,feedback);for(list<string>
52、:iterator ite=ls.begin();ite!=ls.end();ite+)new_connect(*ite,recv_buf);cout<<recv_buf<<endl;void main()cout<<"-"<<endl;cout<<"Server waiting"<<endl;cout<<"-"<<endl;WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2),&wsaData)c
53、out<<"加載winsock失敗!"<<endl;return ;/建立服務器端監聽套接口slisten=socket(AF_INET,SOCK_STREAM, 0); if(slisten=INVALID_SOCKET)cout<<"創建socket失敗!"<<endl;return ;/初始化監聽套接口地址信息ser.sin_family=AF_INET;ser.sin_port=htons(iport);ser.sin_addr.s_addr=INADDR_ANY;/綁定套接口到本地if(bind(slisten,(sockaddr*)&ser, sizeof(sockaddr_in)=SOCKET_ERROR)cout<<"綁定失
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 蕪湖小作坊管理制度
- 英語繪本館管理制度
- 草原屬書屋管理制度
- 膽固醇測定試劑盒分析性能評估資料
- 讓人舒服的溝通技巧
- 財務會計工作職責和內容感想總結范文15篇
- 財務會計業務知識題庫真題
- 試驗檢測師(公共基礎)考試歷年真題題庫(含答案)
- 江蘇省常州市前黃高級中學2025屆高三下學期攀登行動(一)地理試卷(含答案)
- 湖南省2025年中考地理真題(含答案)
- 小學課件培訓:AI賦能教育創新
- 食堂白油使用管理制度
- 個人墊付資金協議書
- 核磁共振與DSA融合技術的臨床應用-全面剖析
- 動火作業施工方案
- 2025春季學期國開電大專科《個人與團隊管理》一平臺在線形考(形考任務3)試題及答案
- 2024年中國資源循環集團有限公司招聘筆試真題
- 露天煤礦安全用電知識課件
- 食品安全自查、從業人員健康管理、進貨查驗記錄、食品安全事故處置等保證食品安全的規章制度
- 美國特殊教育介紹
- 預防保健科室
評論
0/150
提交評論