使用UDP编程完成聊天室,文件传输服务器,电子词典,五子棋。
服务器:
/*===============================================
* 文件名称:ser.c
* 创 建 者:
* 创建日期:2023年08月28日
* 描 述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/stat.h>
#include <signal.h>
#include <pthread.h>
#include <sqlite3.h>
#include <dirent.h>
#include <fcntl.h>
#define ROWS 10
#define COLS 10
typedef struct wm{
int row;
int col;
int flag;
int type;
char name[30];
char destname[30];
char data[100];
}MSG;
typedef struct node{
struct wm user;
struct sockaddr_in addr;
struct node * next;
}*linklist,linknode;
//五子棋行列
typedef struct {
int row;
int col;
}TP;
//回调函数
typedef struct {
int fd;
int len;
struct wm his;
struct sockaddr_in hddr;
}call;
linklist list_create(){
linklist H=(linklist)malloc(sizeof(linknode));
if(NULL==H){
printf("create fail\n");
return NULL;
}
H->next=NULL;
return H;
}
void insert_linklist(MSG msg,struct sockaddr_in cliaddr,linklist p){
linklist t=p;
while(t->next!=NULL){
t=t->next;
}
linklist new=(linklist)malloc(sizeof(linknode));
new->addr=cliaddr;
new->user=msg;
new->next=NULL;
t->next=new;
return;
}
void delete_linklist(linklist p,MSG*msg){
linklist l=p;
linklist pt=NULL;
if(p->next==NULL) {
perror("linklist NULL");
exit(-1);
}
while(l->next!=NULL){
if(strcmp(l->next->user.name,msg->name)==0)
{
if(l->next->next==NULL){
l->next=NULL;
printf("%s从链表中删除\n",msg->name);
break;
}
pt=l->next;
l->next=l->next->next;
printf("%s从链表中删除\n",msg->name);
free(pt);
break;
}
else
{
l=l->next;
}
}
}
void zhuce(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
char *errmsg;
char sql[200]={0};
sprintf(sql,"INSERT INTO usr VALUES('%s','%s')",msg->name,msg->data);
printf("%s\n",sql);
if( sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
sprintf(msg->data,"用户名 %s 已存在",msg->name);
printf("%s\n",msg->data);
}
else
{
sprintf(msg->data,"注册成功!!");
printf("%s\n",msg->data);
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
perror("send error\n");
exit(-1);
}
return;
}
int denglu(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist p){
char *errmsg;
char sql[200]={0};
char **result;
int row;
int col;
printf("%s正在登陆\n",msg->name);
sprintf(sql,"select * from usr where name = '%s' and pass = '%s'",msg->name,msg->data);
if( sqlite3_get_table(db,sql,&result,&row,&col,&errmsg)!=SQLITE_OK)
{
printf("%s",errmsg);
exit(-1);
}
else
{
if(row==0){
sprintf(msg->data,"用户名或密码错误");
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
perror("send error\n");
exit(-1);
}
return -1;
}
else
{
sprintf(msg->data,"denglu success");
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
perror("send error\n");
exit(-1);
}
return 1;
}
}
}
void chat(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist p){
/* linklist pp=p->next;
while(pp!=NULL)
{
sprintf(msg->data,"%s上线啦\n",msg->name);
printf("%s\n",msg->data);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&pp->addr,sizeof(pp->addr)) < 0)
{
perror("sendto\n");
exit(-1);
}
pp=pp->next;
}
*/
char sql[300];
char *errmsg;
char date[100]={0};
linklist q,m,n;
q=p->next;
m=p->next;
n=p->next;
if(q==NULL)
{
perror("linklist NULL");
exit(-1);
}
time_t tm;
struct tm *tmp_ptr = NULL;
time(&tm);
tmp_ptr = localtime(&tm);
sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);
sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,date,msg->data);
printf("%s",date);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
printf("%s\n",errmsg);
exit(-1);
}
while(q!=NULL)
{
if(strcmp(q->user.name,msg->name)==0){
q=q->next;
}
else{
if(strcmp(msg->data,"quit")==0){
sprintf(msg->data,"[%s]已离线",msg->name);
delete_linklist(p,msg);
printf("%s is quit\n",msg->name);
}else{
char temp[100]={0};
strcpy(temp,msg->data);
sprintf(msg->data,"%s\n[%s]:%s\n",date,msg->name,temp);
printf("%s\n",msg->data);
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&q->addr,sizeof(q->addr)) < 0)
{
perror("sendto\n");
exit(-1);
}
else{
q= q->next;
}
}
}
return;
}
//2. 列数3.列的结果 4.列的名字
int hiscallback(void *arg,int num,char** value,char ** name){
call s=*(call*)arg;
sprintf(s.his.data,"%s [%s]:%s",value[1],value[0],value[2]);
sendto(s.fd,&s.his,sizeof(MSG),0,(struct sockaddr *)&(s.hddr),s.len);
return 0;
}
int history(int fd,MSG msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
printf("find chathistory\n");
call c;
c.fd=fd;
c.hddr=cliaddr;
c.len=len;
c.his=msg;
char *errmsg;
if( sqlite3_exec(db ,"select * from record", hiscallback , (void*)&c , &errmsg)!=SQLITE_OK)
{
printf("error:%s\n",errmsg);
sqlite3_free(errmsg);
exit(-1);
}
//解决阻塞
strcpy(msg.data, "*");
if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1)
{
perror("fail to send");
exit(-1);
}
return 1;
}
void siliao(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist q){
printf("in siliao\n");
char sql[300];
char *errmsg;
char date[100]={0};
linklist m=q->next;
linklist n=q->next;
if(m==NULL){
printf("kong linklist\n");
perror("linklist");
exit(-1);
}
else{
printf("%s\n",m->user.name);
printf("链表不为空\n");
}
while(m!=NULL)
{
if(strcmp(m->user.name,msg->destname)==0){
char temp[100]={0};
strcpy(temp,msg->data);
sprintf(msg->data,"%s to %s:%s",msg->name,msg->destname,temp);
printf("%s\n",msg->data);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&m->addr,sizeof(m->addr)) < 0)
{
perror("sendto\n");
exit(-1);
}
else{ printf("send success\n");
time_t tm;
struct tm *tmp_ptr = NULL;
time(&tm);
tmp_ptr = localtime(&tm);
sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);
sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,date,msg->data);
printf("%s",sql);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
printf("%s\n",errmsg);
exit(-1);
}
break;
}
}
else{
m=m->next;
printf("goto next\n");
}
}
if(m==NULL){
printf("destname not exit\n");
sprintf(msg->data,"...[%s] not online",msg->destname);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
{
perror("sendto\n");
exit(-1);
}
}
}
//电子字典
int zidian(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
printf("%s is finding now\n",msg->name);
char *m;
char date[100]={0};
char *errmsg;
char word[100]={0};
int wlen=0;
char sql[300];
char buf[100];
char temp[100];
FILE *fp=fopen("./dict.txt","r");
if(fp==NULL){
perror("open dict fail\n");
exit(-1);
}
printf("open dict success\n");
strcpy(word,msg->data);
wlen=strlen(word);
printf("%s,%d\n",word,wlen);
while(1)
{
char*p=fgets(buf,100,fp);
if(p == NULL){
strcpy(msg->data,"没有这个单词");
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
{
perror("sendto\n");
exit(-1);
}
break;
}
strcpy(temp,buf);
char*q= strtok(buf," ");
if(strcmp(q,msg->data)==0){
printf("strok:%s\n",q);
printf("buf:%s\n",buf);
printf("temp:%s\n",temp);
m=temp+wlen;
while(*m==' ')
{
m++;
}
strcpy(msg->data,m);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
{
perror("sendto\n");
exit(-1);
}
time_t tm;
struct tm *tmp_ptr = NULL;
time(&tm);
tmp_ptr = localtime(&tm);
sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);
sprintf(sql,"insert into zidianrecord values('%s','%s','%s')",msg->name,date,word);
printf("%s",date);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
printf("%s\n",errmsg);
return -1;
}
fclose(fp);
return 1;
}
}
fclose(fp);
return -1;
}
//2. 列数3.列的结果 4.列的名字
int zidiancallback(void *arg,int num,char** value,char ** name){
call d=*(call*)arg;
sprintf(d.his.data,"%s 用户: %s 查找单词: %s",value[1],value[0],value[2]);
sendto(d.fd,&d.his,sizeof(MSG),0,(struct sockaddr *)&(d.hddr),d.len);
return 0;
}
int zidianhis(int fd,MSG msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
call z;
z.fd=fd;
z.hddr=cliaddr;
z.len=len;
z.his=msg;
char *errmsg;
char sql[200]={0};
sprintf(sql,"select * from zidianrecord where name = '%s'",msg.name);
if( sqlite3_exec(db , sql , zidiancallback , (void*)&z , &errmsg)!=SQLITE_OK)
{
printf("error:%s\n",errmsg);
sqlite3_free(errmsg);
exit(-1);
}
//解决阻塞
strcpy(msg.data, "*");
if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
return 1;
}
//文件服务器
void mulu(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
DIR*dirp=opendir(msg->data);
struct dirent* file;
while(file=readdir(dirp)){
strcpy(msg->data,file->d_name);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
}
strcpy(msg->data, "*");
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
return;
}
void scwj(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
int ffd=open(msg->name,O_WRONLY|O_CREAT,0666);
if(fd==-1)
{
printf("open file fail\n");
}
if(0==strcmp(msg->data,"*"))
{
printf("下载完成\n");
close(ffd);
return;
}
write(ffd,msg->data,strlen(msg->data));
}
void xzwj(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
strcat(msg->data,msg->name);
printf("打开%s\n",msg->data);
int ffd = open(msg->data,O_RDONLY);
int ret=0;
memset(msg->data,0,100);
while(1){
ret=read(ffd,msg->data,100);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
if(ret==0){
strcpy(msg->data, "*");
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
break;
}
memset(msg->data,0,100);
}
close(ffd);
return;
}
void gaipass(int fd,MSG *msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
printf("xiugaGi: pass:%s\n name:%s",msg->data,msg->name);
char*errmsg;
char sql[200]={0};
sprintf(sql,"update usr set pass = '%s' where name = '%s'",msg->data,msg->name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
sprintf(msg->data,"修改失败");
printf("%s",errmsg);
exit(-1);
}
else{
sprintf(msg->data,"修改成功");
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
}
void zhuxiao(int fd,MSG *msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
char*errmsg;
char sql[200]={0};
sprintf(sql,"delete from usr where name = '%s'",msg->name);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
sprintf(msg->data,"注销失败...");
printf("%s",errmsg);
exit(-1);
}
else{
sprintf(msg->data,"注销成功!");
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
perror("fail to send");
exit(-1);
}
}
//五子棋
int f=1;
void shunxu(int fd,MSG msg,struct sockaddr_in cliaddr,int len){
msg.flag=f;
printf("%d\n",f);
if(msg.flag==1)
{
sprintf(msg.data,"你是先手");
}
else{
sprintf(msg.data,"你是后手");
}
if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1)
{
perror("send error");
exit(-1);
}
f++;
}
void game(int fd,MSG msg,linklist qi,struct sockaddr_in cliaddr,int len){
printf("进入五子棋游戏\n");
TP tp;
linklist qt;
qt=qi->next;
if(qt==NULL)
{
perror("linklist NULL");
exit(-1);
}
tp.row=msg.row;
tp.col=msg.col;
while(qt!=NULL)
{
if(strcmp(qt->user.name,msg.name)==0){
printf("linknext\n");
qt=qt->next;
}
else{
printf("send game\n");
if(sendto(fd,&tp,sizeof(TP),0,(struct sockaddr *)&qt->addr,sizeof(qt->addr)) < 0)
{
perror("sendto\n");
exit(-1);
}
else{
break;
}
}
}
}
int main(int argc, const char *argv[]){
MSG msg;
sqlite3 *db;
char *errmsg1 = NULL;
char *errmsg2 = NULL;
char *errmsg3 = NULL;
//入参合理性检查
if(3 != argc){
printf("Usage : %s <IP> <PORT>\n", argv[0]);
exit(-1);
}
if(sqlite3_open("my.db",&db)!=SQLITE_OK)
{
printf("%s\n",sqlite3_errmsg(db));
return -1;
}
else{
printf("打开数据库成功\n");
char *sql1 = "create table if not exists usr(name text primary key,pass text)";
int ret1 = sqlite3_exec(db, sql1, NULL, NULL, &errmsg1);
if (ret1!= SQLITE_OK)
{
printf ("用户表创建失败:%s\n", errmsg1);
return -1;
}
char *sql2 = "create table if not exists record(name text , data text , word text)";
int ret2 = sqlite3_exec(db, sql2, NULL, NULL, &errmsg2);
if (ret2 != SQLITE_OK)
{
printf ("用户表创建失败:%s\n", errmsg2);
return -1;
}
char *sql3= "create table if not exists zidianrecord(name text , data text , word text)";
int ret3 = sqlite3_exec(db, sql3, NULL, NULL, &errmsg3);
if (ret3 != SQLITE_OK)
{
printf ("用户表创建失败:%s\n", errmsg3);
return -1;
}
}
//创建用户数据报套接字
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == fd){
ERRLOG("socket error");
}
//填充网络信息结构体
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t serveraddr_len = sizeof(serveraddr);
//3.绑定
if(-1 == bind(fd, (struct sockaddr *)&serveraddr, serveraddr_len)){
ERRLOG("bind error");
}
//定义结构体保存客户端的信息
//如果使用UDP时不保存客户端的网络信息结构体
//可以接受到客户端发来的数据 但是没法回信给客户端 因为sendto的后两个参数需要用到
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
linklist p=list_create();//群聊
linklist q=list_create();//私聊
linklist qi=list_create();//五子棋
while(1){
int ret =recvfrom(fd,&msg,sizeof(MSG), 0, (struct sockaddr *)&cliaddr, &len);
if(ret>0)
{
switch(msg.type)
{
case 1:
zhuce(fd,&msg,db,cliaddr,len);
break;
case 2:
if(denglu(fd,&msg,db,cliaddr,len,p)==1){
insert_linklist(msg,cliaddr,p);
insert_linklist(msg,cliaddr,q);
break;
}else{
break;}
case 3:
chat(fd,&msg,db,cliaddr,len,p);
break;
case 4:
history(fd,msg,db,cliaddr,len);
break;
case 5:
siliao(fd,&msg,db,cliaddr,len,q);
break;
case 6:
zidian(fd,&msg,db,cliaddr,len);
break;
case 7:
zidianhis(fd,msg,db,cliaddr,len);
break;
case 8:
mulu(fd,&msg,cliaddr,len);
break;
case 9:
scwj(fd,&msg,cliaddr,len);
break;
case 10:
xzwj(fd,&msg,cliaddr,len);
break;
case 11:
gaipass(fd,&msg,db,cliaddr,len);
break;
case 12:
zhuxiao(fd,&msg,db,cliaddr,len);
break;
case 13:
shunxu(fd,msg,cliaddr,len);
insert_linklist(msg,cliaddr,qi);
break;
case 14:
game(fd,msg,qi,cliaddr,len);
break;
defalut:
printf("recv error\n");
}
}
}
close(fd);
return 0;
}
客户端
/*===============================================
* 文件名称:cli.c
* 创 建 者:
* 创建日期:2023年08月28日
* 描 述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ROWS 10
#define COLS 10
typedef struct wm{
int row;
int col;
int flag;
int type;
char name[30];
char destname[30];
char data[100];
}MSG;
typedef struct {
int row;
int col;
}TP;
int show_connect()
{
printf("正在连接服务器,请稍候...\n");
int i, num = 1;
const char* pic = "|/-\\"; //简单动画特效
while(1)
{
if(101 == num) //当num自增到101时,进度条已满。显示Loading成功信息,并跳出死循环。
{
break;
}
printf("[");
for(i = 0; i < num/10; i++) //当进度前进10个点时,刷新一次进度条。
printf("*"); //以'*'充当进度条。
printf("]");
printf("%d%%...%c\r", num++, pic[num%4]); //'\r'为回车符。
fflush(stdout); //清空标准输出缓冲区中多余的数据。
usleep(40000); //这里通过修改睡眠时间来控制进度条更新速度。
}
return 0;
}
//动态显示进度条
int show_login()
{
printf("正在登陆,请稍候...\n");
int i, num = 1;
const char* pic = "|/-\\"; //简单动画特效
while(1)
{
if(101 == num) //当num自增到101时,进度条已满。显示Loading成功信息,并跳出死循环。
{
printf("\n登陆成功!!\n");
sleep(1);
break;
}
printf("[");
for(i = 0; i < num/10; i++) //当进度前进10个点时,刷新一次进度条。
printf("*"); //以'*'充当进度条。
printf("]");
printf("%d%%...%c\r", num++, pic[num%4]); //'\r'为回车符。
fflush(stdout); //清空标准输出缓冲区中多余的数据。
usleep(40000); //这里通过修改睡眠时间来控制进度条更新速度。
}
return 0;
}
void zhuce(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=1;
printf("\033[1;33m输入网名\n");
fgets(msg->name,30,stdin);
msg->name[strlen(msg->name)-1]='\0';
printf("\033[0;35m输入密码\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,NULL,NULL)==-1)
{
perror("recv 失败");
exit(-1);
}
printf("%s\n",msg->data);
return;
}
int denglu(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=2;
printf("\033[1;36m输入网名\n");
fgets(msg->name,30,stdin);
msg->name[strlen(msg->name)-1]='\0';
printf("\033[0;33m输入密码\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,NULL,NULL)==-1)
{
perror("recv 失败");
exit(-1);
}
if(strncmp(msg->data,"denglu success",14)==0){
show_login();
printf("\033[0;35m%s,欢迎回来!!\n",msg->name);
return 1;
}else{
printf("\033[1;33m%s\n",msg->data);
return -1;
}
}
void chat(int fd,MSG*msg,struct sockaddr_in saddr,int len){
MSG*temp;
msg->type=3;
/* if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("历史失败");
exit(-1);
}
*/
pid_t pid= fork();
if(pid<0){
perror("fork");
exit(-1);
}
else if(pid==0)
{
while(1)
{
//接收
// memset(temp->name,0,sizeof(temp->data));
// memset(temp->data,0,sizeof(temp->data));
if(recvfrom(fd,temp,sizeof(MSG),0,NULL,NULL)==-1)
{
perror("recv 失败");
exit(-1);
}
printf("\033[1;33m%s\n",temp->data);
}
}
else{
//发送
while(1){
// memset(msg->data,0,sizeof(msg->data));
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(strcmp(msg->data,"quit")==0)
{
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
kill(pid,SIGKILL);
wait(NULL);
break;
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
}
}
// close(fd);
return;
}
int history(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=4;
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("历史失败");
exit(-1);
}
while(1){
memset(msg->data,0,sizeof(msg->data));
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
//解决阻塞
if(0==strcmp(msg->data,"*"))
{
break;
}
printf("%s\n",msg->data);
}
return 1;
}
void siliao(int fd,MSG*msg,struct sockaddr_in saddr,int len){
MSG*temp;
msg->type=5;
printf("请输入你要连接人的名字\n");
fgets(msg->destname,30,stdin);
msg->destname[strlen(msg->destname)-1]='\0';
printf("输入你想要发送的数据\n");
pid_t pid=fork();
if(pid<0){
perror("fork\n");
exit(-1);
}
else if(pid==0)
{
while(1)
{
//接收
// memset(temp->name,0,sizeof(temp->data));
// memset(temp->data,0,sizeof(temp->data));
if(recvfrom(fd,temp,sizeof(MSG),0,NULL,NULL)==-1)
{
perror("recv 失败");
exit(-1);
}
printf("\033[1;33m%s\n",temp->data);
}
}
else{
//发送
while(1){
// memset(msg->data,0,sizeof(msg->data));
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(strcmp(msg->data,"quit")==0)
{
kill(pid,SIGKILL);
wait(NULL);
exit(1);
break;
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
}
}
close(fd);
return;
}
void zidian(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=6;
while(1)
{
memset(msg->data,0,100);
printf("\033[1;32m输入要查找的单词(q)结束\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if (0 == strcmp(msg->data, "q"))
{
printf("quit \n");
break;
}
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send 失败");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
printf("\033[0;33m%s\n",msg->data);
}
//close(fd);
return;
}
int zidianhis(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=7;
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("历史失败");
exit(-1);
}
while(1){
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
//解决阻塞
if(0==strcmp(msg->data,"*"))
{
break;
}
printf("%s\n",msg->data);
}
return 1;
}
void mulu(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=8;
printf("\033[1;32m输入要查看的目录\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("发送失败");
exit(-1);
}
while(1){
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
if(0==strcmp(msg->data,"*"))
{
break;
}
printf("%s\n",msg->data);
}
}
void scwj(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=9;
char buf[100]={0};
char buf2[100]={0};
printf("请输入你要上传到服务器哪个路径\n");
fgets(buf,100,stdin);
buf[strlen(buf)-1]='\0';
printf("请输入你要上传的文件名\n");
fgets(buf2,100,stdin);
buf2[strlen(buf2)-1]='\0';
strcat(buf,buf2);
strcpy(msg->name,buf);
int ffd = open(buf2,O_RDONLY);
int ret=-1;
memset(msg->data,0,100);
while(1){
ret=read(ffd,msg->data,100);
if(ret==0){
strcpy(msg->data, "*");
sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&saddr,len);
printf("上传完成\n");
return;
}
sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&saddr,len);
memset(msg->data,0,100);
}
close(ffd);
}
void xzwj(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=10;
printf("请输入你要下载服务器哪个路径下的文件\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
printf("请输入你要下载的文件名\n");
fgets(msg->name,100,stdin);
msg->name[strlen(msg->name)-1]='\0';
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("发送失败");
exit(-1);
}
int ffd=open(msg->name,O_RDWR|O_CREAT,0666);
while(1){
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
if(0==strcmp(msg->data,"*"))
{
break;
}
write(ffd,msg->data,strlen(msg->data));
}
printf("下载完成\n");
close(ffd);
return;
}
void gaipass(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=11;
printf("请输入你要修改的密码\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("历史失败");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
printf("%s\n",msg->data);
}
void zhuxiao(int fd,MSG*msg,struct sockaddr_in saddr,int len){
msg->type=12;
printf("确认要注销账户?y/n\n");
fgets(msg->data,100,stdin);
msg->data[strlen(msg->data)-1]='\0';
if(strcmp(msg->data,"n")==0){
return;
}
else if(strcmp(msg->data,"y")==0){
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send error");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv error");
exit(-1);
}
else{
printf("%s\n",msg->data);
return;
}
}
else{
printf("输入有误\n");
}
}
//五子棋
//打印棋盘
//初始化棋盘
void Initmap(char map[ROWS][COLS],int row, int col)
{
memset(map,' ',row*col*sizeof(char));
}
void Printmap(char map[ROWS][COLS],int row,int col)
{
int i = 0;
printf("\033[0m 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10\n");
for(; i < row;i++)
{
printf("%2d ",i+1);
int j = 0;
for(; j < col;j++)
{
if( j == col-1 )
{
printf(" %c \n",map[i][j]);
if(i != row-1)
printf(" ---|---|---|---|---|---|---|---|---|---\n");
break;
}
printf(" %c ",map[i][j]);
printf("|");
}
}
}
//判断棋盘是否满了
int IsFall(char map[ROWS][COLS])
{
size_t i = 0;
for(; i < ROWS;i++)
{
size_t j = 0;
for(; j < COLS; j++)
{
if(map[i][j] == ' ')
return 0;
}
}
return 1;
}
//移动
void CommonMove(char map[ROWS][COLS],MSG* msg,char ch)
{
if(msg == NULL)
{
return;
}
int x = msg->row;
int y = msg->col;
//如果棋盘满了的话就退出循环,也就是不能再下子了
while(1)
{
if(x >= 0 && x < ROWS && y >= 0 && y < COLS){
if(map[x][y] == ' ')
{
map[x][y] = ch;
msg->row = x;
msg->col = y;
break;
}
else
{
printf("坐标输入有误,请重新输入坐标: ");
scanf("%d%d",&x,&y);
x--;
y--;
}
}
else{
printf("坐标输入有误,请重新输入坐标: ");
scanf("%d%d",&x,&y);
x--;
y--;
}
}
}
//客户端移动
void Cli1Move(char map[ROWS][COLS],MSG* msg)
{
CommonMove(map,msg,'@');
}
//服务器移动
void Cli2Move(char map[ROWS][COLS],MSG* msg)
{
CommonMove(map,msg,'O');
}
//列齐
int ColState(char map[ROWS][COLS],MSG* msg)
{
int x = msg->row;
int y = msg->col;
int count = 1;
while(x-1 >= 0)
{
if(map[x][y] != map[x-1][y])
break;
count++;
if(count == 5)
{
//如果往上遍历已经够了五个,说明已经赢了,直接返回
return count;
}
x--;
}
//到这里说明当前点往上走是不满足条件的
//但是已经走到了最上面的点,所以从临界点往相反方向找
//必须要找到五个连续的才算满足条件
count = 1;//count 重新被设定为1
while(x+1 <= ROWS)
{
if(map[x][y] == map[x+1][y])
{
count++;
if(count == 5)
{
return count;
}
x++;
}
else
{
//n 代表当前状态未满足赢的条件
return 0;
}
}
return 0;
}
//行齐
int RowState(char map[ROWS][COLS],MSG* msg)
{
int x = msg->row;
int y = msg->col;
int count = 1;
while(y-1 >= 0)
{
if(map[x][y] != map[x][y-1])
break;
count++;
if(count == 5)
{
//如果往左遍历已经够了五个,说明已经赢了,直接返回
return count;
}
y--;
}
//到这里说明当前点往左走是不满足条件的
//但是已经走到了最左面的点,所以从临界点往相反方向找
//必须要找到五个连续的才算满足条件
count = 1;//count 重新被设定为1
while(y+1 <= COLS)
{
if(map[x][y] == map[x][y+1])
{
count++;
if(count == 5)
{
return count;
}
y++;
}
else
{
//n 代表当前状态未满足赢的条件
return 0;
}
}
return 0;
}
//左上到右下的对角线
int UpLeftState(char map[ROWS][COLS],MSG* msg)
{
int x = msg->row;
int y = msg->col;
int count = 1;
while(x-1 >= 0 && y-1 >= 0 )
{
if(map[x][y] != map[x-1][y-1])
break;
count++;
if(count == 5)
{
//如果往左上遍历已经够了五个,说明已经赢了,直接返回
return count;
}
x--;
y--;
}
//到这里说明当前点往左上走是不满足条件的
//但是已经走到了最左上的点,所以从临界点往相反方向找
//必须要找到五个连续的才算满足条件
count = 1;//count 重新被设定为1
while(x+1 <= ROWS && y+1 <= COLS)
{
if(map[x][y] == map[x+1][y+1])
{
count++;
if(count == 5)
{
return count;
}
x++;
y++;
}
else
{
//n 代表当前状态未满足赢的条件
return 0;
}
}
return 0;
}
//右上到左下的对角线
int UpRightState(char map[ROWS][COLS], MSG* msg)
{
int x = msg->row;
int y = msg->col;
int count = 1;
while(x-1 >= 0 && y+1 <= COLS)
{
if(map[x][y] != map[x-1][y+1])
break;
count++;
if(count == 5)
{
//如果往右上遍历已经够了五个,说明已经赢了,直接返回
return count;
}
x--;
y++;
}
//到这里说明当前点往右上走是不满足条件的
//但是已经走到了最右上面的点,所以从临界点往相反方向找
//必须要找到五个连续的才算满足条件
count = 1;//count 重新被设定为1
while(x+1 <= ROWS && y-1 <=COLS)
{
if(map[x][y] == map[x+1][y-1])
{
count++;
if(count == 5)
{
return count;
}
x++;
y--;
}
else
{
//n 代表当前状态未满足赢的条件
return 0;
}
}
return 0;
}
//返回游戏进行状态
char GameState(char map[ROWS][COLS],MSG* msg)
{
if(msg == NULL)
{
return 'e';
}
//判断当前点所在列是否是连续五个子儿
if(ColState(map,msg) == 5)
{
return map[msg->row][msg->col];
}
//判断当前点所在行是否是连续五个子儿
else if(RowState(map,msg) == 5)
{
return map[msg->row][msg->col];
}
//判断当前点所在左上与右下的对角线是否满足条件
else if(UpLeftState(map,msg) == 5)
{
return map[msg->row][msg->col];
}
//判断当前点所在左上与右下的对角线是否满足条件
else if(UpRightState(map,msg) == 5)
{
return map[msg->row][msg->col];
}
else if(IsFall(map))
{
//平局
return 'p';
}
//当前没有输赢,继续游戏
return 'g';
}
void Game(int fd,MSG*msg,struct sockaddr_in saddr,int len,int flag)
{
msg->type=14;
char map[ROWS][COLS];
TP tp;
Initmap(map,ROWS,COLS);
Printmap(map,ROWS,COLS);
int x,y=0;
if(flag==1){
while(1){
msg->row=0;
msg->col=0;
printf("你是先手请下子@(输入坐标)> ");
scanf("%d%d",&x,&y);
getchar();
msg->row = x-1;
msg->col = y-1;
Cli1Move(map,msg);
Printmap(map,ROWS,COLS);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send error");
exit(-1);
}
if(GameState(map,msg) == '@')
{
printf("你赢啦!\n");
break;
}
else if(GameState(map,msg) == 'p')
{
printf("平局!\n");
break;
}
printf("等待对方输入... \n");
if(recvfrom(fd,&tp,sizeof(TP),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
msg->row=tp.row;
msg->col=tp.col;
Cli2Move(map,msg);
Printmap(map,ROWS,COLS);
if(GameState(map,msg) == 'O')
{
printf("你输啦!\n");
break;
}
else if(GameState(map,msg) == 'p')
{
printf("平局!\n");
break;
}
}
}
else if(flag==2) {
while(1){
msg->row=0;
msg->col=0;
printf("你是后手等待对方输入... \n");
if(recvfrom(fd,&tp,sizeof(TP),0,(struct sockaddr*)&saddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
msg->row=tp.row;
msg->col=tp.col;
printf("收到服务器消息\n");
Cli1Move(map,msg);
Printmap(map,ROWS,COLS);
if(GameState(map,msg) == '@')
{
printf("你输啦!\n");
break;
}
else if(GameState(map,msg) == 'p')
{
printf("平局!\n");
break;
}
printf("到你下棋了请下子O(输入坐标)> ");
scanf("%d%d",&x,&y);
getchar();
msg->row = x-1;
msg->col = y-1;
Cli2Move(map,msg);
Printmap(map,ROWS,COLS);
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
{
perror("send error");
exit(-1);
}
if(GameState(map,msg) == 'O')
{
printf("你赢啦!\n");
break;
}
else if(GameState(map,msg) == 'p')
{
printf("平局!\n");
break;
}
}
}
else{
printf("房间已满\n");
}
}
int f=-1;
void shunxu(int fd,MSG*msg,struct sockaddr_in seraddr,int len){
msg->type=13;
if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&seraddr,len)==-1)
{
perror("send error");
exit(-1);
}
if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&seraddr,&len)==-1)
{
perror("recv 失败");
exit(-1);
}
f=msg->flag;
printf("%s\n",msg->data);
}
void chat_menu(int fd,MSG*msg,struct sockaddr_in saddr,int len){
int n;
while(1) {
printf("\033[1;35m🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈\n");
// printf("\033[1;31m登陆成功!你来啦! %s !\n",msg->name);
printf("\033[1;31m 使用功能 \n");
printf("\033[1;36m1 .加入群聊 \033[1;33m2 .聊天记录\n");
printf("\033[1;34m3 .加入悄悄话\033[1;32m4 .电子字典\n");
printf("\033[1;36m5 .查字典记录\033[1;33m6 .服务器目录\n");
printf("\033[1;34m7 .上传文件 \033[1;32m8 .下载文件\n");
printf("\033[1;31m9 .修改密码 \033[1;37m10.注销账号\n");
printf("\033[1;32m11.下棋顺序 \033[1;34m12.双人五子棋\n");
printf("\033[1;31m13.退出\n");
printf("\033[1;35m🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈\n");
int sc=scanf("%d",&n);
if(sc==-1){
perror("scanf\n");
exit(-1);
}
getchar();
switch(n)
{
case 1:
chat(fd,msg,saddr,len);
break;
case 2:
history(fd,msg,saddr,len);
break;
case 3:
siliao(fd,msg,saddr,len);
break;
case 4:
zidian(fd,msg,saddr,len);
break;
case 5:
zidianhis(fd,msg,saddr,len);
break;
case 6:
mulu(fd,msg,saddr,len);
break;
case 7:
scwj(fd,msg,saddr,len);
break;
case 8:
xzwj(fd,msg,saddr,len);
break;
case 9:
gaipass(fd,msg,saddr,len);
return;
case 10:
zhuxiao(fd,msg,saddr,len);
return;
case 11:
shunxu(fd,msg,saddr,len);
break;
case 12:
Game(fd,msg,saddr,len,f);
break;
case 13:
printf("\033[1;36m感谢使用,欢迎下次再来\n");
close(fd);
exit(0);
return;
default:
printf("\033[1;31m输入错误\n");
break;
}
}
return;
}
int main(int argc, const char *argv[]){
//入参合理性检查
if(3 != argc){
printf("Usage : %s <IP> <PORT>\n", argv[0]);
exit(-1);
}
show_connect();
//1.创建用户数据报套接字
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == fd){
ERRLOG("socket error");
}
//2.填充服务器的网络信息结构体
struct sockaddr_in seraddr;
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(atoi(argv[2]));
seraddr.sin_addr.s_addr = inet_addr(argv[1]);
int len = sizeof(seraddr);
int choose;
while(1){
MSG msg;
printf("\033[1;35m🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵\n");
printf("\033[1;33m 欢迎使用系统 \n");
printf("\033[1;36m 选择功能 \n");
printf("\033[1;31m1.注册 \033[1;35m2.登陆 \033[1;32m3.退出\n");
printf("\033[1;35m🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵\n");
int sc=scanf("%d",&choose);
if(sc==-1){
perror("scanf\n");
exit(-1);
}
getchar();
switch(choose)
{
case 1:
zhuce(fd,&msg,seraddr,len);
break;
case 2:
if(denglu(fd,&msg,seraddr,len)==1){
chat_menu(fd,&msg,seraddr,len);
}
break;
case 3:
printf("\033[1;34m感谢使用,欢迎下次再来\n");
close(fd);
exit(0);
default:
printf("\033[1;34m输入错了请重新输入\n");
}
}
return 0;
}
运行结果: