採用了客戶器/服務器模式,實現了基於UDP客戶端之間的相互通訊,其優勢有:在服務器端具備維護客戶端我的信息,記錄客戶端狀態,分配帳號,服務器地址和端口的配置等。客戶端上也實現了,地址及端口的設置用戶註冊和用戶登陸,添加好友及刪除好友,查看好友是否在線,給好友發送消息等。可是不足的是,咱們沒有設計GUI窗口界面沒有更加美觀,而是用簡潔的代碼直接在運行中顯示菜單欄;沒有作出咱們理想中的黑名單,咱們本意上是打算實現黑名單功能,設置成黑名單的人不能發消息給我,除了黑名單的均可以發,只容許好友發,這個打算由於能力有限,並無實現;接收緩衝區有延遲,處理不及時,須要先接收完上次數據才能夠繼續接受數據;羣聊功能沒有實現,只能私聊單個客戶端對客戶端的通訊;發送和接受不能以多線程的方式同時進行,消息須要咱們主動去接受。前端
服務器菜單:
數據庫
服務器端口配置:
windows
查看當前全部帳戶:數組
開啓服務器:
服務器
客戶端菜單:
網絡
修改IP和端口號:
多線程
註冊帳號:
socket
登陸:
ui
查看好友列表(空):
spa
ID1003添加好友:
查看1003和1004好友:
狀態值爲1爲在線,0爲離線:
1004發送信息至1003:
1003接受信息:
刪除好友:
UDP是OSI 參考模型中一種無鏈接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務, UDP在IP報文的協議號是17。UDP協議的主要做用是將網絡數據流量壓縮成數據包的形式。一個典型的數據包就是一個二進制數據的傳輸單位。每個數據包的前8個字節用來包含報頭信息,剩餘字節則用來包含具體的傳輸數據。
UDP報文沒有可靠性保證、順序保證和流量控制字段等,可靠性較差。可是正由於UDP協議的控制選項較少,在數據傳輸過程當中延遲小、數據傳輸效率高,適合對可靠性要求不高的應用程序,或者能夠保障可靠性的應用程序,如DNS、TFTP、SNMP等。
客戶端/服務器(C/S)模式結構的基本原則是將計算機應用任務分解成多個子任務,由多臺計算機分工完成,即採用「功能分佈」原則。客戶端完成數據處理,數據表示以及用戶接口功能;服務器端完成DBMS(數據庫管理系統)的核心功能。這種客戶請求服務、服務器提供服務的處理方式是一種新型的計算機應用模式。
採用客戶端/服務器(C/S)模式;客戶端利用UDP與服務器鏈接,客戶端與客戶端之間經過UDP互相通信;服務器端具備服務器端口設置,維護客戶端我的信息,記錄客戶端狀態,分配帳號等功能。客戶端具備服務器地址及端口設置,用戶註冊,用戶登錄,添加好友和刪除好友,查看好友信息,給好友發送消息等功能;服務器與客戶端間、客戶端之間的交互採用控制檯方式方式。主要是用規定好的格式發送字符信息。
data.h #include <Winsock2.h> struct Friends { int id; int ava; //是否有效 1 有效 ,0 無效 }; struct User { int id; char name[15]; int online; //是否在線 1 在線 ,0 離線 char passwd[15]; sockaddr_in addr; Friends friends[50]; }; server.h #include "data.h" #include <string> using namespace std; //#include "net.cpp" //net.cpp void serverStart(User user[], int po); //user.cpp void saveFile(User user[]); void readFile(User user[]); int login(User user[], char str[]); int reg(User user[], char str[]); string watch(User user[], char str[]); int delF(User user[], char str[]); int addF(User user[], char str[]); user.cpp #include "data.h" #include <string.h> #include <stdio.h> #include <string> using namespace std; //#include <stdio.h> //從文件讀取 void readFile(User user[]) { } //保存到文件 void saveFile(User user[]) { } //用戶登陸判斷 int login(User user[], char str[]) { int id; char passwd[15]; //char passwd1[15]; sscanf(str, "%d %[^'\0']", &id, passwd); //接收用戶發送的id 和 密碼 //sprintf(passwd,"%s'\0'",passwd1); printf("登陸判斷:%d %s \n", id, passwd); //int size = sizeof(user) / sizeof(user[0]); for (int i = 0; user[i].id != -1; i++) { printf("當前 id : %d %s \n", user[i].id, user[i].passwd); if (user[i].id == id) { //id匹配判斷 printf("id == id : %d %s \n", user[i].id, user[i].passwd); if (strcmp(user[i].passwd, passwd) == 0) { //密碼匹配判斷 user[i].online = 1; return i; } else return -1; //return i; } } return -1; } //用戶註冊 int reg(User user[], char str[]) { //User p; //int id = 1000; char name[15]; char passwd[15]; sscanf(str, "%s %s", name, passwd); //讀取用戶名 密碼 for (int i = 0; user[i].id != -1; i++) //找到user表最後一個(id=-1) { /* if(strcmp(User[i].id, id) == 0) { id++; } else break;*/ } if (user[i].id == -1) { //新用戶數據保存到user裏 user[i].id = user[i - 1].id + 1; user[i].online = 0; //user[i].name=name; //user[i].passwd=passwd; strcpy(user[i].name, name); strcpy(user[i].passwd, passwd); user[i].friends[0].id = -1; user[i + 1].id = -1; user[i + 1].friends[0].id = -1; return i; } return -1; } //查看用戶好友列表 string watch(User user[], char str[]) { int id; //char buf[1024]; string st = "好友列表: \n-------\n"; sscanf(str, "%d", &id); printf("\n --%d \n", id); for (int i = 0; user[i].id != -1; i++) { //先找到用戶再user的下標,再經過friends數組反向找好友的user下標,便可獲取信息 if (user[i].id == id) { printf("匹配到 %d \n", user[i].id); for (int j = 0; user[i].friends[j].id != -1; j++) { printf("user[i].friends[j].id = %d \n", user[i].friends[j].id); if (user[i].friends[j].ava != 0) { int k = 0; for (k = 0; user[k].id != -1; k++) { if (user[k].id == user[i].friends[j].id) break; } char temp[100]; sprintf(temp, "ID : %d 用戶名: %s 狀態: %d \n", user[k].id, user[k].name, user[k].online); //itoa //st = st + "ID : " + user[k].id + " 用戶名: " + user[k].name + " 狀態: " + user[k].online + "\n"; st = st + temp; } } //st = st + '\0'; //char* buf = (char*)st.data(); //printf("%s",buf); //return buf; return st; } } return "error"; } //刪除好友 int delF(User user[], char str[]) { int Uid, Fid, uid, fid; sscanf(str, "%d %d", &uid, &fid); printf("delF: %d %d \n", uid, fid); for (Uid = 0; user[Uid].id != -1; Uid++) { if (user[Uid].id == uid) { break; } } //Uid--; //if(user[Uid].id==-1) return -1; for (Fid = 0; user[Fid].id != -1; Fid++) { if (user[Fid].id == fid) { break; } } //Fid--; //if(user[Fid].id==-1) return -1; //雙向刪除好友 int i = 0; for (i = 0; user[Uid].friends[i].id != -1; i++) { if (user[Uid].friends[i].id == fid) { user[Uid].friends[i].ava = 0; break; } } for (i = 0; user[Fid].friends[i].id != -1; i++) { if (user[Fid].friends[i].id == uid) { user[Fid].friends[i].ava = 0; break; } } return 1; } //添加好友 int addF(User user[], char str[]) { int Uid, Fid, uid, fid; sscanf(str, "%d %d", &uid, &fid); printf("addF: %d %d \n", uid, fid); for (Uid = 0; user[Uid].id != -1; Uid++) { if (user[Uid].id == uid) { break; } } //Uid--; //if(user[Uid].id==-1) return -1; for (Fid = 0; user[Fid].id != -1; Fid++) { if (user[Fid].id == fid) { break; } } //Fid--; //if(user[Fid].id==-1) return -1; printf("Uid %d Fid %d \n", Uid, Fid); //雙向添加好友 printf("* 0 *\n"); int i = 0; for (i = 0; user[Uid].friends[i].id != -1; i++) { if (user[Uid].friends[i].id == uid) return -1; } printf("* 1 *\n"); if (user[Uid].friends[i].id == -1) { user[Uid].friends[i].id = fid; user[Uid].friends[i].ava = 1; user[Uid].friends[i + 1].id = -1; user[Uid].friends[i + 1].ava = 0; } printf("* 2 *\n"); for (i = 0; user[Fid].friends[i].id != -1; i++) { if (user[Fid].friends[i].id == fid) return -1; } printf("* 3 *\n"); if (user[Fid].friends[i].id == -1) { user[Fid].friends[i].id = uid; user[Fid].friends[i].ava = 1; user[Fid].friends[i + 1].id = -1; user[Fid].friends[i + 1].ava = 0; } printf("* 4 *\n"); return 1; } net.cpp #include <Winsock2.h> #include <stdio.h> #include "server.h" //#include "data.h" void serverStart(User user[], int po) { //加載套接字庫 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本 HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本 { WSACleanup(); return; } printf("server is operating!\n\n"); //建立用於監聽的UDP套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN addrSrv; //定義sockSrv發送和接收數據包的地址 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; //addrSrv.sin_port = htons(6000); addrSrv.sin_port = htons(po); //綁定套接字, 綁定到端口 bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); //將套接字設爲監聽模式, 準備接收客戶請求 SOCKADDR_IN addrClient; //用來接收客戶端的地址信息 int len = sizeof(SOCKADDR); //char recvBuf[1024]; //收 //char sendBuf[1024]; //發 //char tempBuf[1024]; //存儲中間信息數據 while (1) { char *recvBuf = new char[1024]; //接收數據 char *sendBuf = new char[1024]; //發送數據 char *tempBuf = new char[1024]; //臨時數據 //等待並數據 recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrClient, &len); //sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf); //printf("info -> %s \n",tempBuf); char type; //char msg[1024]; char *msg = new char[1024]; //將收到的信息進行拆分判斷 sscanf(recvBuf, "%c %[^\n]", &type, msg); int res = 0; printf("消息類型: %c \n", type); //printf(" Msg: %s \n",msg); switch (type) { case 'L': //登陸 res = login(user, msg); if (res != -1) { user[res].addr = addrClient; //保存 user[res].online = 1; sendto(sockSrv, "登陸成功", strlen("登陸成功") + 1, 0, (SOCKADDR *)&addrClient, len); } else { sendto(sockSrv, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrClient, len); } break; case 'S': //發送 { int id, i, f = 0; char sendMsg[1024]; sscanf(msg, "%d %s", &id, sendMsg); //拆分信息 printf("id: %d", id); printf("msg: %s", sendMsg); for (i = 0; user[i].id != -1; i++) { if (user[i].id == id) { //匹配發送方id if (user[i].online == 1) { //對方在線 char newsend[1024]; sprintf(newsend, "%s -> %s \n", user[i].name, sendMsg); sendto(sockSrv, newsend, strlen(newsend) + 1, 0, (SOCKADDR *)&user[i].addr, len); sendto(sockSrv, "發送成功", strlen("發送成功") + 1, 0, (SOCKADDR *)&addrClient, len); //往發送方返回成功信息 f = 1; } else sendto(sockSrv, "對方不在線", strlen("對方不在線") + 1, 0, (SOCKADDR *)&addrClient, len); //不在線 } } if (f == 0) sendto(sockSrv, "對方不存在", strlen("對方不存在") + 1, 0, (SOCKADDR *)&addrClient, len); //不存在 break; } case 'R': //註冊 { res = reg(user, msg); char buf[1024]; sprintf(buf, "你的ID : %d , 你的名字 : %s , 你的密碼 : %s\n", user[res].id, user[res].name, user[res].passwd); /*if(res!=-1){ user[res].addr = addrClient; user[res].online = 1; } else { sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len); }*/ sendto(sockSrv, buf, strlen(buf) + 1, 0, (SOCKADDR *)&addrClient, len); //返回註冊信息 break; } case 'F': //好友功能 { char type2, more[50]; sscanf(msg, "%c %[^\n]", &type2, more); printf("-- %c %s --\n", type2, more); switch (type2) { case 'A': //添加好友 addF(user, more); sendto(sockSrv, "add ok", strlen("add ok") + 1, 0, (SOCKADDR *)&addrClient, len); break; case 'D': //刪除好友 delF(user, more); sendto(sockSrv, "del ok", strlen("del ok") + 1, 0, (SOCKADDR *)&addrClient, len); break; case 'W': //查看好友 //char bufW[512]; string st = watch(user, more); char *bufW = (char *)st.data(); //char* bufW = watch(user , more ); printf("%s", bufW); sendto(sockSrv, bufW, strlen(bufW) + 1, 0, (SOCKADDR *)&addrClient, len); break; } } break; case 'Q': //退出 { int my = -1, i = 0; sscanf(msg, "%d", &my); for (i = 0; user[i].id != -1; i++) { if (user[i].id == my) { user[i].online = 0; //下線 } } sendto(sockSrv, "退出成功", strlen("退出成功") + 1, 0, (SOCKADDR *)&addrClient, len); break; } default: //不是格式輸入 sendto(sockSrv, "請按格式輸入", strlen("請按格式輸入") + 1, 0, (SOCKADDR *)&addrClient, len); break; } /* if('q' == recvBuf[0]) { sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len); printf("Chat end!\n"); break; }*/ //sprintf_s(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf); /* sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf); printf("%s\n",tempBuf);*/ //發送數據 /* printf("Please input data: \n"); gets(sendBuf); sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);*/ } closesocket(sockSrv); WSACleanup(); } server.cpp #include "server.h" #include <stdio.h> #include <string> #include <stdlib.h> #include <conio.h> using namespace std; //#include "data.h" int po = 8089; void PortConfig() { system("cls"); printf("當前端口號 : %d ,請輸入新端口號:", po); scanf("%d", &po); printf("新的端口號爲 : %d\n回車返回", po); getchar(); getchar(); } //端口配置 void Mainte(User user[]) { system("cls"); printf("1.查看信息 2.修改信息\n請輸入:"); char ch; ch = getch(); system("cls"); if ('1' == ch) for (int i = 0; user[i].id != -1; i++) { printf("第%d條記錄->ID:%d 用戶名:%s 密碼:%s \n", i, user[i].id, user[i].name, user[i].passwd); } else { int id, i; char name[15]; char passwd[15]; printf("請輸入id:"); scanf("%d", &id); printf("請輸入名字:"); scanf("%s", name); printf("請輸入密碼:"); scanf("%s", passwd); printf("你的輸入: %d %s %s\n", id, name, passwd); for (i = 0; user[i].id != -1; i++) { if (user[i].id == id) { system("cls"); printf("匹配到 %d", user[i].id); //sprintf(user[i].name,"%s",name); //sprintf(user[i].name,"%s",passwd); //printf(" %s ",user[i].name); //printf("原記錄->ID:%d 用戶名:%s 密碼:%s \n",i,user[i].id,user[i].name,user[i].passwd); strcpy(user[i].name, name); strcpy(user[i].passwd, passwd); //printf(" %s ",user[i].name); printf("更改爲功->ID:%d 用戶名:%s 密碼:%s \n", user[i].id, user[i].name, user[i].passwd); break; } } } getchar(); getchar(); } //維護客戶端我的信息 void Start(User user[]) { serverStart(user, po); } //開啓服務器 void Distr(User user[]) { system("cls"); char buf[50]; int i; printf("請輸入名字 密碼:"); scanf("%[^\n]", buf); i = reg(user, buf); if (i != -1) { printf("新註冊賬號 -> ID:%d 用戶名:%s 密碼:%s \n", user[i].id, user[i].name, user[i].passwd); } else printf("建立失敗!回車返回"); getchar(); getchar(); } //分配帳號 void MenuShow() { system("cls"); printf("***************************************************************************************************************\n"); printf(" |>> Server <<| \n\n"); printf(" |>> 1.服務器 端口 配置 <<| \n\n"); printf(" |>> 2.維護客戶端我的信息 <<| \n\n"); printf(" |>> 3.開啓 服務器 <<| \n\n"); printf(" |>> 4.分 配 帳 號 <<| \n\n"); printf(" |>> 5.退 出 <<| \n\n"); printf("***************************************************************************************************************\n"); } void SMenu(User user[]) { int f = 1; while (f) { MenuShow(); printf("選擇以上編號:"); char i; i = getch(); switch (i) { case '1': { PortConfig(); break; } case '2': { Mainte(user); break; } case '3': { system("cls"); Start(user); break; } case '4': { Distr(user); break; } case '5': f = 0; break; default: { printf("輸入錯誤!"); break; } } } } //服務器端菜單選擇 void main() { User user[50]; //初始化 user 表 //user[0]=new User; user[0].id = 1001; user[0].online = 0; strcpy(user[0].name, "b"); strcpy(user[0].passwd, "1001"); user[0].friends[0].id = -1; //user[0].name = "b"; //user[0].passwd = "1001"; //printf("%s %s",user[0].name,user[0].passwd); //user[1]=new User; user[1].id = 1002; user[1].online = 0; strcpy(user[1].name, "c"); strcpy(user[1].passwd, "1002"); user[1].friends[0].id = -1; //user[1].name = "b"; //user[1].passwd = "1001"; //user[2]=new User; user[2].id = -1; user[2].online = 0; user[2].friends[0].id = -1; //serverStart(user,8089); SMenu(user); }
client.h void sendAll(char ipaddr[],int port); int sendM(SOCKET sockSrv,char ipaddr[],int port,char sendBuf[],sockaddr_in addrSrv); client.cpp #include <Winsock2.h> #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <conio.h> #include "client.h" // 必須的頭文件 //程序入口 int main() { char ipaddr[25] = "127.0.0.1"; int port = 8089; /* WORD wVersionRequested; WSADATA wsaData; int err; int id; wVersionRequested = MAKEWORD(1,1); err = WSAStartup(wVersionRequested, &wsaData); if(err != 0) { return 5; } if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return 5; } printf("Client is operating!\n\n"); SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0); sockaddr_in addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port);*/ int len = sizeof(SOCKADDR); while (1) { system("cls"); printf("***************************************************************************************************************\n\n"); printf(" |>> Client <<| \n\n"); printf(" |>> 1.服務器地址和端口配置 <<| \n\n"); printf(" |>> 2.賬號註冊 <<| \n\n"); printf(" |>> 3.用戶登陸 <<| \n\n"); printf(" |>> 4.退出 <<| \n\n"); printf("***************************************************************************************************************\n\n"); printf("請輸入:"); char ch; ch = getch(); switch (ch) { case '1': //修改配置 { char ipA[15]; int po; system("cls"); printf("請輸入IP:"); scanf("%s", ipA); printf("請輸入端口:"); scanf("%d", &po); strcpy(ipaddr, ipA); port = po; printf("修改爲功"); getchar(); getchar(); } break; case '2': //添加用戶 { WORD wVersionRequested; WSADATA wsaData; int err; int id; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return 5; } if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本 HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本 { WSACleanup(); return 5; } printf("Client is operating!\n\n"); //建立用於監聽的套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port); int len = sizeof(SOCKADDR); system("cls"); printf("請輸入用戶名 密碼:"); char buf[100], msg[100]; scanf("%[^\n]", buf); sprintf(msg, "R %s", buf); sendM(sockSrv, ipaddr, port, msg, addrSrv); getchar(); getchar(); break; } case '3': //登陸 system("cls"); sendAll(ipaddr, port); break; case '4': default: return 0; } } } send.cpp #include <Winsock2.h> #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <conio.h> // 必須的頭文件 /* struct Args{ int s; void *buf; int len; unsigned int flags; struct sockaddr *from; int *fromlen; }; DWORD WINAPI ThreadFunc(LPVOID lp); */ int sendM(SOCKET sockSrv, char ipaddr[], int port, char sendBuf[], sockaddr_in addrSrv) { //加載套接字庫 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本 HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本 { WSACleanup(); return -1; } printf("Client is operating!\n\n"); //建立用於監聽的套接字 //SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0); /*sockaddr_in addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port);*/ int len = sizeof(SOCKADDR); char *recvBuf = new char[1024]; //char *sendBuf=new char[1024]; char *tempBuf = new char[1024]; //scanf("%[^\n]",sendBuf); //printf("%s",sendBuf); if ('!' != sendBuf[0]) sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len); //等待並數據 int res = 0; res = recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrSrv, &len); if (res == -1) printf("暫時無數據!\n"); else printf("%s \n", recvBuf); if ('q' == recvBuf[0]) { return 1; //sendto(sockSrv,"Q",strlen("Q")+1,0,(SOCKADDR*)&addrSrv,len); //printf("Chat end!\n"); } //sprintf(tempBuf,"%s say : %s",inet_ntoa(addrSrv.sin_addr),recvBuf); //scanf(recvBuf,"%[^'\0']",tempBuf); //sprintf(tempBuf,"temp: \n %[^'\0']",recvBuf); //printf("temp : \n%s \n\n",tempBuf); //發送數據 //closesocket(sockSrv); WSACleanup(); return 0; } sendAll.cpp #include <Winsock2.h> #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <conio.h> #include "client.h" // 必須的頭文件 /* struct Args{ int s; void *buf; int len; unsigned int flags; struct sockaddr *from; int *fromlen; }; DWORD WINAPI ThreadFunc(LPVOID lp); */ void sendAll(char ipaddr[], int port) { //加載套接字庫 WORD wVersionRequested; WSADATA wsaData; int err; int id; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本 HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本 { WSACleanup(); return; } printf("Client is operating!\n\n"); //建立用於監聽的套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port); int len = sizeof(SOCKADDR); int f = 1; while (f) { //登陸 char buf[1024], msg[1024]; printf("請輸入ID:"); scanf("%d", &id); printf("請輸入密碼:"); //getch(); scanf("%s", buf); sprintf(msg, "L %d %s", id, buf); f = sendM(sockSrv, ipaddr, port, msg, addrSrv); //向服務器發送登陸信息 if (f) { printf("登陸失敗!回車返回"); getchar(); getchar(); return; } getchar(); getchar(); } f = 1; int op = 0; while (f) { char *recvBuf = new char[1024]; char *sendBuf = new char[1024]; char *tempBuf = new char[1024]; char ch; //printf("Please input data: \n"); printf("1.查看好友 2.發送信息 3.接收信息 4.添加好友 5.刪除好友 6.退出: \n"); //gets(sendBuf); ch = getch(); char in[1024]; switch (ch) { case '1': //查看好友 sprintf(sendBuf, "F W %d", id); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; case '2': //發送信息 printf("請輸入:對方id 信息\n"); scanf("%[^\n]", in); sprintf(sendBuf, "S %s", in); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; case '3': //接收信息 sprintf(sendBuf, "!"); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; case '4': //添加好友 { int dstid; printf("請輸入:對方id\n"); scanf("%d", &dstid); sprintf(sendBuf, "F A %d %d", id, dstid); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; } case '5': //刪除好友 { int dstid; printf("請輸入:對方id\n"); scanf("%d", &dstid); sprintf(sendBuf, "F D %d %d", id, dstid); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; } default: f = 0; sprintf(sendBuf, "Q %d", id); sendM(sockSrv, ipaddr, port, sendBuf, addrSrv); break; } continue; //scanf("%[^\n]",sendBuf); //printf("%s",sendBuf); if ('!' != sendBuf[0]) sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len); //等待並數據 if ('Q' == sendBuf[0]) { sendto(sockSrv, "Q", strlen("Q") + 1, 0, (SOCKADDR *)&addrSrv, len); printf("Chat end!\n"); break; } recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrSrv, &len); if ('q' == recvBuf[0]) { sendto(sockSrv, "Q", strlen("Q") + 1, 0, (SOCKADDR *)&addrSrv, len); printf("Chat end!\n"); break; //printf("Chat end!\n"); } printf("%s \n", recvBuf); //發送數據 } closesocket(sockSrv); WSACleanup(); }