任务目标
- 聊天器采用客户端/服务器(C/S)模式;
- 客户端利用UDP与服务器相连,客户端与客户端之间通过UDP相互通信;
- 服务器端具有服务器端口设置维护客户端个人信息,记录客户端状态,分配账号等;
- 客户端具有服务器地址及端口设置,用户注册,用户登陆,添加好友和删除好友,查看好友信息,给好友发送消息等功能;
- 服务器与客户端间、客户端之间的交互采用控制台方式或GUI窗口方式均可;
完成情况
采用了客户器/服务器模式,实现了基于UDP客户端之间的相互通信,其优点有:在服务器端具有维护客户端个人信息,记录客户端状态,分配账号,服务器地址和端口的配置等。客户端上也实现了,地址及端口的设置用户注册和用户登录,添加好友及删除好友,查看好友是否在线,给好友发送消息等。但是不足的是,我们没有设计GUI窗口界面没有更加美观,而是用简洁的代码直接在运行中显示菜单栏;没有做出我们理想中的黑名单,我们本意上是打算实现黑名单功能,设置成黑名单的人不能发消息给我,除了黑名单的都可以发,只允许好友发,这个打算因为能力有限,并没有实现;接收缓冲区有延迟,处理不及时,需要先接收完上次数据才可以继续接受数据;群聊功能没有实现,只能私聊单个客户端对客户端的通信;发送和接受不能以多线程的方式同时进行,消息需要我们主动去接受。
运行效果图
服务器菜单:
服务器端口配置:
查看当前所有账户:
开启服务器:
客户端菜单:
修改IP和端口号:
注册账号:
登录:
查看好友列表(空):
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();
}