采用了客户器/服务器模式,实现了基于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(); }