我写了一个简单的聊天程序,服务器和客户端接受发送数据都通过定义的同一个结构体,为什么在本机测试,开两个终端都没有问题,客户端和服务器分开在不同的电脑上测试时,客户端发送数据正常,而此时服务器收到的结构体里的数据为空是怎么回事?服务器用的epoll单线程,客户端用的双线程
4条回答 默认 最新
- rotation ㅤ 2016-08-19 13:33关注
服务器代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"message.h"#define PORT 6666 //服务器端口
#define LISTEN_SIZE 1024 //连接请求队列的最大长度
#define EPOLL_SIZE 1024 //监听的客户端的最大数目
#define BUF_MAX 257 //读取缓存区最大字节time_t timep; //记录当前时间
typedef struct cli_data //记录在线用户信息的结构体
{
int cli_fd; //记录连接的用户套接字
char username[21]; //记录账号,最大20位
struct cli_data* next;
}cli_data;
typedef struct user //记录用户账号信息的结构体
{
char username[21];
char pwd[21];
}user;
typedef struct group
{
char username[100][21];
int groupfd[100];
char groupname[21];
int n;
}group;
group taolun[100]; //全局讨论组
char* my_time() //输出当前时间
{
time(&timep);
char* p=ctime(&timep);
return p;
}cli_data* head; //创建头结点
cli_data* create() //创建一个带头节点的链表,储存已连接的用户
{
cli_data* head;
head=(cli_data*)malloc(sizeof(struct cli_data));
head->next=NULL;
return head;
}
cli_data* insert() //插入链表
{cli_data* temp=head; cli_data* new; new=(cli_data*)malloc(sizeof(cli_data)); new->next=NULL; while(temp->next!=NULL) { temp=temp->next; } temp->next=new; return new;
}
void delete(cli_data* head,int cli_fd) //链表的删除
{
cli_data* temp,*last;
temp=head->next;
last=head;
while(temp!=NULL&&temp->cli_fd!=cli_fd)
{
last=temp;
temp=temp->next;
}
if(temp!=NULL&&temp->cli_fd==cli_fd)
{
last->next=temp->next;
free(temp);
}
}
void my_err(char* string)
{
perror(string);
exit(1);
}
void my_path(char*dir,char* filename,char* path) //将目录和文件名连接成一个路径
{
strcpy(path,dir);
strcat(path,"/");
strcat(path,filename);
}
void send_message(struct message recv_buf,int conn_fd) //向客户端发送信息
{
struct message send_buf;
send_buf=recv_buf;
int n=send_buf.n;
int fd;
struct user user_data;
int ret=0; //用来表示注册账号是否存在或账号密码信息是否匹配
FILE* fp;
cli_data* temp; //在线用户链表临时指针
char path[256]; //储存文件路径
char friendname[21]; //储存用户好友用户名
int i=0;
fp=fopen("passwd.txt","a+");
fclose(fp);switch(n) { case 0: { //注册账号 if((fd=open("passwd.txt",O_RDWR|O_APPEND))<0) { my_err("open"); } while(read(fd,&user_data,sizeof(struct user))>0) { if(strcmp(user_data.username,send_buf.username)==0) { send_buf.n=-2; ret=1; break; } } if(!ret) { strcpy(user_data.username,recv_buf.username); strcpy(user_data.pwd,recv_buf.pwd1); send_buf.n=22; if(write(fd,&user_data,sizeof(struct user))<0) { my_err("write"); } close(fd); int fd,stdoutfd; fd=open("log_file",O_RDWR|O_CREAT|O_APPEND); stdoutfd=dup(1); printf("a user register,username:%s,time:%s",user_data.username,my_time()); dup2(fd,1); printf("a user register,username:%s,time:%s",user_data.username,my_time()); dup2(stdoutfd,1); close(fd); close(stdoutfd); mkdir(user_data.username,07777); //创建用户所属目录 my_path(user_data.username,user_data.username,path); fd=open(path,O_RDWR|O_CREAT|O_APPEND,0777); if(fd<0) { printf("创建用户好友文件失败\n"); } close(fd); } if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送数据失败\n"); } break; } case 1: {//登陆 if((fd=open("passwd.txt",O_RDONLY))<0) { my_err("open"); } while(read(fd,&user_data,sizeof(struct user))>0) { if(strcmp(user_data.username,send_buf.username)==0) { if(strcmp(user_data.pwd,send_buf.pwd1)==0) { ret=1; break; } } } if(ret) send_buf.n=11; else send_buf.n=-1; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送数据失败\n"); return; } if(send_buf.n==11) { int fd,stdoutfd; fd=open("log_file",O_CREAT|O_RDWR|O_APPEND); printf("a user is login,username:%s,time:%s",send_buf.username,my_time()); stdoutfd=dup(1); dup2(fd,1); printf("a user is login,username:%s,time:%s",send_buf.username,my_time()); dup2(stdoutfd,1); close(fd); close(stdoutfd); temp=insert(); temp->cli_fd=conn_fd; strcpy(temp->username,send_buf.username); my_path("lixian",send_buf.username,path); //发送离线消息 fd=open(path,O_RDONLY); if(fd>0) { send_buf.n=6; while(read(fd,send_buf.time,sizeof(send_buf.time))!=0) { read(fd,send_buf.from,sizeof(send_buf.from)); read(fd,send_buf.chat,sizeof(send_buf.chat)); if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客服端发送离线消息失败\n"); return; } } close(fd); fd=open(path,O_RDWR|O_CREAT|O_TRUNC); close(fd); } } break; } case 3: { //添加好友 temp=head->next; my_path(send_buf.from,send_buf.from,path); //防止重复添加好友 fd=open(path,O_RDONLY); if(fd<0) { printf("打开用户好友文件失败\n"); return; } while(read(fd,friendname,sizeof(friendname))!=0) { if(strcmp(friendname,send_buf.to)==0) { send_buf.n=-3; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送数据失败\n"); return; } close(fd); return; } } while(temp!=NULL) { if(strcmp(temp->username,send_buf.to)==0) //找到指定在线好友 { ret=1; break; } temp=temp->next; } if(ret) { int to_fd=temp->cli_fd; //向另一用户征求是否同意添加好友 send(to_fd,&send_buf,sizeof(struct message),0); recv(to_fd,&send_buf,sizeof(struct message),0); if(send_buf.n==33) { my_path(send_buf.from,send_buf.from,path);//写入用户好友文件 fd=open(path,O_RDWR|O_APPEND); if(write(fd,&send_buf.to,sizeof(send_buf.to))<0) { printf("写入用户好友失败\n"); send_buf.n=-3; } close(fd); my_path(send_buf.from,send_buf.to,path); //创建用户与该好友的聊天记录文件 fd=open(path,O_RDWR|O_CREAT|O_TRUNC,0777); close(fd); my_path(send_buf.to,send_buf.to,path); //写入另一用户好友文件 fd=open(path,O_RDWR|O_APPEND); write(fd,&send_buf.from,sizeof(send_buf.from)); close(fd); my_path(send_buf.to,send_buf.from,path); //创建另一用户与该好友的聊天记录文件 fd=open(path,O_RDWR|O_CREAT|O_TRUNC,0777); close(fd); } } else send_buf.n=-3; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("send error\n"); } break; } case 4: {//查看好友列表 my_path(recv_buf.username,recv_buf.username,path); //连接用户好友文件路径 fd=open(path,O_RDONLY); while(read(fd,send_buf.friendname[i++],sizeof(recv_buf.username))!=0); send_buf.friendname[i][0]='\0'; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("send error\n"); } break;} case 44: { //查看在线好友 my_path(recv_buf.username,recv_buf.username,path); //连接用户好友文件路径 fd=open(path,O_RDONLY); while(read(fd,friendname,sizeof(friendname))!=0) { int n=0; temp=head->next; while(temp!=NULL) { if(strcmp(temp->username,friendname)==0) { n=1; break; } else temp=temp->next; } if(n) { strcpy(send_buf.friendname[i++],friendname); } } send_buf.friendname[i][0]='\0'; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("send error\n"); } break; } case 5: //删除好友 { int i=0; int ret=0; my_path(send_buf.from,send_buf.from,path); fd=open(path,O_RDONLY); if(fd<0) { printf("打开用户好友文件失败\n"); send_buf.n=-5; } while(read(fd,send_buf.friendname[i++],sizeof(send_buf.username))!=0) send_buf.friendname[i][0]='\0'; i=0; close(fd); while(strlen(send_buf.friendname[i])!=0) { if(strcmp(send_buf.friendname[i],send_buf.to)==0) { strcpy(send_buf.friendname[i],"\n"); ret++; } i++; } fd=open(path,O_RDWR|O_CREAT|O_TRUNC); if(fd<0) { printf("打开用户好友文件失败\n"); send_buf.n=-5; } i=0; while(strlen(send_buf.friendname[i])!=0) { if(strcmp(send_buf.friendname[i],"\n")!=0) { if(write(fd,send_buf.friendname[i],sizeof(send_buf.username))<0) { printf("写入用户好友文件失败\n"); send_buf.n=-5; } } i++; } close(fd); i=0; my_path(send_buf.to,send_buf.to,path); fd=open(path,O_RDONLY); //读取删除对象的好友列表 if(fd<0) { printf("打开删除对象好友文件失败\n"); send_buf.n=-5; } while(read(fd,send_buf.friendname[i++],sizeof(send_buf.username))!=0); send_buf.friendname[i][0]='\0'; close(fd); i=0; while(strlen(send_buf.friendname[i])!=0) { if(strcmp(send_buf.friendname[i],send_buf.from)==0) strcpy(send_buf.friendname[i],"\n"); i++; } i=0; fd=open(path,O_RDWR|O_CREAT|O_TRUNC); if(fd<0) { printf("打开删除对象好友文件失败\n"); send_buf.n=-5; } while(strlen(send_buf.friendname[i])!=0) { if(strcmp(send_buf.friendname[i],"\n")!=0) { if(write(fd,send_buf.friendname[i],sizeof(send_buf.username))<0) { printf("写入删除对象好友文件失败\n"); send_buf.n=-5; } } i++; } close(fd); ret++; if(ret==2) send_buf.n=55; else send_buf.n=-5; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送信息失败\n"); return; } break; } case 6: //私聊 { int i=0,ret=0; my_path(send_buf.from,send_buf.from,path); fd=open(path,O_RDONLY); while(read(fd,send_buf.friendname[i++],sizeof(send_buf.username))!=0); send_buf.friendname[i][0]='\0'; close(fd); i=0; while(strlen(send_buf.friendname[i])!=0) { if(strcmp(send_buf.friendname[i],send_buf.to)==0) { ret=1; break; } i++; } if(ret) { temp=head->next; while(temp!=NULL) { if(strcmp(temp->username,send_buf.to)==0) { my_path(send_buf.from,send_buf.to,path); fd=open(path,O_RDWR|O_CREAT|O_APPEND); if(fd<0) { printf("打开记录用户聊天记录文件失败\n"); } if(send(temp->cli_fd,&send_buf,sizeof(struct message),0)<0) { printf("发送用户消息失败\n"); return; } else { int stdoutfd=dup(1); dup2(fd,1); printf("%s",send_buf.time); printf("我@%s:%s\n",send_buf.to,send_buf.chat); dup2(stdoutfd,1); close(fd); my_path(send_buf.to,send_buf.from,path); open(path,O_RDWR|O_CREAT|O_APPEND); if(fd<0) { printf("打开记录用户聊天记录文件失败\n"); return; } dup2(fd,1); printf("%s",send_buf.time); printf("%s@我:%s\n",send_buf.from,send_buf.chat); dup2(stdoutfd,1); close(fd); close(stdoutfd); return; } } temp=temp->next; } my_path("lixian",send_buf.to,path); fd=open(path,O_RDWR|O_CREAT|O_APPEND,0777); if(fd<0) { printf("打开指定用户离线消息文件\n"); return; } write(fd,send_buf.time,sizeof(send_buf.time)); write(fd,send_buf.from,sizeof(send_buf.from)); write(fd,send_buf.chat,sizeof(send_buf.chat)); close(fd); } else { send_buf.n=-6; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送信息失败\n"); return; } } break; } case 77: //创建讨论组 { int i=1; while(taolun[i].n!=0) i++; if(i<100) { taolun[i].n=1; send_buf.groupi=i; strcpy(taolun[i].username[0],send_buf.from); strcpy(taolun[i].groupname,send_buf.groupname); taolun[i].groupfd[0]=conn_fd; } else send_buf.n=-77; if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户发送信息失败\n"); return; } break; } case 777: //邀请在线好友加入讨论组 { int ret=0; int i=0; my_path(send_buf.from,send_buf.from,path); fd=open(path,O_RDONLY); if(fd<0) { printf("打开用户好友文件失败\n"); send_buf.n=-777; } while(read(fd,send_buf.friendname[i],sizeof(send_buf.username))!=0) { if(strcmp(send_buf.to,send_buf.friendname[i])==0) { ret=1; break; } } if(ret) { temp=head->next; while(temp!=NULL) { if(strcmp(send_buf.to,temp->username)==0) { int j=0,k=send_buf.groupi; send(temp->cli_fd,&send_buf,sizeof(struct message),0); while(taolun[k].groupfd[j]!=0) { j++; } taolun[k].groupfd[j]=temp->cli_fd; strcpy(taolun[k].username[j],send_buf.to); return; } temp=temp->next; } } send_buf.n=-777; send(conn_fd,&send_buf,sizeof(struct message),0); break; } case 7: //群聊 { int i=send_buf.groupi,j=0; while(taolun[i].groupfd[j]!=0) { if(taolun[i].groupfd[j]!=conn_fd&&taolun[i].groupfd[j]!=-1) { send(taolun[i].groupfd[j],&send_buf,sizeof(struct message),0); } j++; } break; } case -7: //退出讨论组 { int i=send_buf.groupi,j=0; while(taolun[i].groupfd[j]!=conn_fd) { j++; } if(j==0) { j=1; send_buf.n=-7777; while(taolun[i].groupfd[j]!=0&&taolun[i].groupfd[j]!=-1) { send(taolun[i].groupfd[j],&send_buf,sizeof(struct message),0); j++; } taolun[i].n=0; memset(&taolun[i],0,sizeof(taolun[i])); } else taolun[i].groupfd[j]=-1; break; } case 7777: //查看讨论组成员 { int i=send_buf.groupi,j=0,k=0;; while(taolun[i].groupfd[j]!=0&&taolun[i].groupfd[j]!=-1) { strcpy(send_buf.friendname[k++],taolun[i].username[j]); j++; } send_buf.friendname[k][0]='\0'; send(conn_fd,&send_buf,sizeof(struct message),0); break; } case 8: //查看与好友聊天记录 { int j=0,ret=0; send_buf.n=-8; temp=head->next; my_path(send_buf.from,send_buf.from,path); fd=open(path,O_RDONLY); while(read(fd,send_buf.friendname[j++],sizeof(send_buf.username))!=0); send_buf.friendname[j][0]='\0'; j=0; while(strlen(send_buf.friendname[j])!=0) { if(strcmp(send_buf.to,send_buf.friendname[j])==0) { ret=1; break; } j++; } if(ret) { FILE * fp; j=0; my_path(send_buf.from,send_buf.to,path); fp=fopen(path,"r+"); while(!feof(fp)) { fgets(send_buf.chathistory[j],10000,fp); j++; if(j==100) break; } send_buf.n=8; } if(send(conn_fd,&send_buf,sizeof(struct message),0)<0) { printf("向客户端发送数据失败\n"); return; } } }
}
int main()
{
int sock_fd,conn_fd; //储存套接字
struct sockaddr_in cli_addr,serv_addr;
struct message recv_buf; //读取缓存区
socklen_t cli_len;
int epollfd;
struct epoll_event event;
struct epoll_event* events;
int fd;memset(taolun,0,sizeof(taolun)); fd=open("log_file",O_RDWR|O_CREAT|O_APPEND); close(fd); //创建一个套接字 sock_fd=socket(AF_INET,SOCK_STREAM,0); if(sock_fd<0) { my_err("socket"); } //设置该套接字使之可以重新绑定端口 int optval=1; if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,(void*)&optval,sizeof(int))<0) { my_err("setsockopt"); } //初始化服务器端地址结构 memset(&serv_addr,0,sizeof(struct sockaddr_in)); serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(PORT); serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(sock_fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in))<0) { my_err("bind"); } //将套接字转化为监听套接字 if(listen(sock_fd,LISTEN_SIZE)<0) { my_err("listen"); } cli_len=sizeof(struct sockaddr_in); events=(struct epoll_event*)malloc(sizeof(struct epoll_event)*EPOLL_SIZE); //创建一个监听描述符epoll,并将监听套接字加入 epollfd=epoll_create(EPOLL_SIZE); if(epollfd==-1) { my_err("epoll_create"); } event.events = EPOLLIN; event.data.fd = sock_fd; if(epoll_ctl(epollfd,EPOLL_CTL_ADD,sock_fd,&event)<0) { my_err("epoll_ctl"); } mkdir("lixian",0777); //创建离线消息目录 head=create(); //创建链表 while(1) { int sum=0,i; sum=epoll_wait(epollfd,events,EPOLL_SIZE,-1); for(i=0;i<sum;i++) { if(events[i].data.fd==sock_fd) //有请求连接 { int fd,stdoutfd; fd=open("log_file",O_RDWR|O_CREAT|O_APPEND); stdoutfd=dup(1); conn_fd=accept(sock_fd,(struct sockaddr*)&cli_addr,&cli_len); if(conn_fd<0) { my_err("accept"); } event.events = EPOLLIN | EPOLLRDHUP; event.data.fd = conn_fd; if(epoll_ctl(epollfd,EPOLL_CTL_ADD,conn_fd,&event)<0) //将新连接的套接字加入监听 { my_err("epoll_ctl"); } printf("a connet is connected,ip is %s,time:%s",inet_ntoa(cli_addr.sin_addr),my_time()); dup2(fd,1); printf("a connet is connected,ip is %s,time:%s",inet_ntoa(cli_addr.sin_addr),my_time()); dup2(stdoutfd,1); close(fd); close(stdoutfd); } else if(events[i].events&EPOLLIN) //有可读的套接字 { memset(&recv_buf,0,sizeof(struct message)); recv(events[i].data.fd,&recv_buf,sizeof(struct message),0); send_message(recv_buf,events[i].data.fd); } if(events[i].events&EPOLLRDHUP) { int fd,stdoutfd; fd=open("log_file",O_RDWR|O_CREAT|O_APPEND); stdoutfd=dup(1); delete(head,events[i].data.fd); printf("a connet is quit,ip is %s,time:%s",inet_ntoa(cli_addr.sin_addr),my_time()); dup2(fd,1); printf("a connet is quit,ip is %s,time:%s",inet_ntoa(cli_addr.sin_addr),my_time()); dup2(stdoutfd,1); close(fd); close(stdoutfd); epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&event); close(events[i].data.fd); } } } return 0;
}
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报
悬赏问题
- ¥15 为什么openeluer里面按不了python3呢?
- ¥15 关于#matlab#的问题:训练序列与输入层维度不一样
- ¥15 关于Ubuntu20.04.3LTS遇到的问题:在安装完CUDA驱动后,电脑会进入卡死的情况,但可以通过键盘按键进入安全重启,但重启完又会进入该情况!
- ¥15 关于#嵌入式硬件#的问题:树莓派第一天重装配置python和opencv后第二天打开就成这样,瞎捣鼓搞出来文件夹还是没把原来的界面调回来
- ¥20 Arduino 循迹小车程序电路出错故障求解
- ¥20 Arduino 循迹小车程序电路出错故障求解
- ¥15 AT89C52单片机C语言串口助手发送数据包返回值
- ¥15 C++数组中找第二小的数字程序纠错
- ¥15 wannier复现图像时berry曲率极值点与高对称点严重偏移
- ¥15 利用决策森林为什么会出现这样·的问题(关键词-情感分析)