任务目标

  1. 聊天器采用客户端/服务器(C/S)模式;
  2. 客户端利用UDP与服务器相连,客户端与客户端之间通过UDP相互通信;
  3. 服务器端具有服务器端口设置维护客户端个人信息,记录客户端状态,分配账号等;
  4. 客户端具有服务器地址及端口设置,用户注册,用户登陆,添加好友和删除好友,查看好友信息,给好友发送消息等功能;
  5. 服务器与客户端间、客户端之间的交互采用控制台方式或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();
}

最新文章

  1. CENTOS 6.5 平台离线安装 Apache2.4
  2. getElementsByClassName 兼容性
  3. ***PHP中empty()和isset()的区别
  4. Ant学习---第五节:Ant_Junit介绍(基于3的版本)
  5. jQuery 滚动动画简单版
  6. 从汇编来看c语言
  7. 在WPF中自定义你的绘制(四)
  8. PAT (Advanced Level) 1004. Counting Leaves (30)
  9. 在linux下利用信号量实现一个写者线程多个读者线程
  10. mongodb 创建用户
  11. this的学习
  12. 微信小程序获取二维码参数
  13. Java最小化镜像制作
  14. (后端)Java新人入职——配置环境及安装开发工具(完全)
  15. WIFI探针技术
  16. STM32 定时器级联
  17. linux服务器rz命令上传文件
  18. flume配置文件
  19. React-Native 在android写不支持gif的解决方案!
  20. Nginx搭建成功后,无法访问Tomcat问题

热门文章

  1. 查看服务器配置信息prtdiag与systeminfo实用命令
  2. Oauth服务端协议开发
  3. 使用Zxing生成一维码和二维码
  4. spring aop xml中配置实例
  5. hdu 3530 区间和在一定范围内最长区间
  6. Html+CSS二周目---&gt;常用概念
  7. hibernate课程 初探一对多映射1-1 课程简介
  8. mongodb客户端操作常用命令
  9. vue中 eCharts 自适应容器
  10. (C# 基础) 接口