#include <myhead.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__:",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.1.5"
#define PORT 8888
//用户中发送的消息属性结构体
typedef struct
{
char type; //'L':群聊 'C':群聊 'q':下线
char name[20]; //用户名
char text[128]; //信息内容
}msg_c;
//用户地址信息链表
typedef struct node
{
struct sockaddr_in cin; //客户端地址信息
struct node*next;
}linklist_t;
//链表函数声明
linklist_t* linklist_create();
linklist_t* node_buy(struct sockaddr_in cin);
int head_insert(linklist_t *q,struct sockaddr_in cin);
void login(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin);
void chat(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin);
void quit(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin);
void system_msg(int sfd,msg_c msg,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{ //创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success sfd=%d\n",sfd);
//填充服务器的地址信息结构体,给bind函数使用
struct sockaddr_in sin;
sin.sin_family =AF_INET; //地址族
sin.sin_port =htons(PORT); //服务器端口
sin.sin_addr.s_addr =inet_addr(IP); //服务器ip
//绑定服务器地址信息
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success\n");
//创建客户端地址信息结构体
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
//创建单项循环链表存储客户信息
linklist_t* q=linklist_create();
if(NULL==q)
{
return -1;
}
//创建子进程
pid_t cpid=fork();
// 接收消息
if(cpid<0)
{
msg_c msg;
while(1)
{
if(recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen)<0) //接收客户端的信息
{
ERR_MSG("recv");
return -1;
}
//打印接收信息
printf("%c %s\n",msg.type,msg.name);
//判断接收消息类型
switch(msg.type)
{
case 'L':
{
login(q,sfd,msg,cin);
}
break;
case 'C':
{
chat(q,sfd,msg,cin);
}
break;
case 'q':
{
//下线函数
quit(q,sfd,msg,cin);
break;
}
default:
printf("输入错误我\n");
break;
}
}
}
//发送服务器消息
else if(0==cpid)
{
msg_c msg;
msg.type='C';
strcpy(msg.name,"<系统消息>");
while(1)
{
scanf("%s",msg.text);
while(getchar()!=10);
system_msg(sfd,msg,sin);
}
}
else
{
ERR_MSG("fork");
return -1;
}
close(sfd);
return 0;
}
//申请头结点函数
linklist_t* linklist_create()
{
linklist_t* q=(linklist_t*)malloc(sizeof(linklist_t));
if(NULL==q)
{
printf("创建失败\n");
return NULL;
}
//初始化头结点
q->next=q;
return q;
}
//申请结点函数
linklist_t *node_buy(struct sockaddr_in cin)
{
linklist_t *q=(linklist_t*)malloc(sizeof(linklist_t));
if(NULL==q)
{
printf("申请失败\n");
return NULL;
}
q->cin=cin;
q->next=NULL;
return q;
}
//链表头插函数
int head_insert(linklist_t* q,struct sockaddr_in cin)
{
if(NULL==q)
{
printf("insert error\n");
return -1;
}
//创建普通结点
linklist_t* newNode=node_buy(cin);
if(NULL==newNode)
{
printf("create error\n");
return -1;
}
//插入结点
newNode->next=q->next;
q->next=newNode;
return 0;
}
void login(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin)
{
//校验是否存在在线用户
if(q->next)
{
//设置用户消息属性
msg.type='C';
//遍历当前在线客户端
linklist_t* temp=q;
while(temp->next!=q)
{
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&temp->next->cin,\
sizeof(temp->next->cin))==-1)
{
ERR_MSG("sendto");
continue;
}
//跳到下一个用户
temp=temp->next;
}
}
head_insert(q,cin);
printf("用户[%s]:登录信息广播成功\n",msg.name);
}
//客户端群发信息函数
void chat(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin)
{
//将客户端信息转发给其他在线的客户端
//校验是否存在在线用户
if(q->next)
{
linklist_t* temp=q;
while(temp->next!=q)
{
//判断当前用户是否是发消息的用户
if(temp->next->cin.sin_port==cin.sin_port)
{
temp=temp->next;//跳过当前用户
continue;//跳过本次循环
}
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&temp->next->cin,\
sizeof(temp->next->cin))==-1)
{
ERR_MSG("sendto");
continue;
}
temp=temp->next;
}
}
printf("用户[%s]:客户端群聊信息成功广播\n",msg.name);
}
//客户端下线函数
void quit(linklist_t* q,int sfd,msg_c msg,struct sockaddr_in cin)
{
//将客户端下线信息转发给其他在线的客户端
//校验是否存在在线用户
if(q->next)
{
msg.type='C';
strcpy(msg.text,"老子下线了");
//遍历当前在线客户端
linklist_t* temp=q;
while(temp->next!=q)
{
//判断当前用户是否是要下线的用户(遍历判断)
if(temp->next->cin.sin_port==cin.sin_port)
{
linklist_t* delete_c=temp->next;//标记下线用户
temp->next=temp->next->next;//孤立
free(delete_c);//删除用户
delete_c=NULL;//指针置空防止野指针
continue;
}
//给所有用户发送该用户的下线信息
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&temp->next->cin,\
sizeof(temp->next->cin))==-1)
{
ERR_MSG("sendto");
continue;
}
temp=temp->next;
}
}
printf("用户[%s]:客户端下线信息广播成功\n",msg.name);
}
//服务器端发送信息函数
void system_msg(int sfd,msg_c msg,struct sockaddr_in sin)
{
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
ERR_MSG("sendto");
}
}
#include <myhead.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__:",__LINE__);\
perror(msg);\
}while(0)
#define SET_PORT 8888
#define SET_IP "192.168.1.5"
//用户发送的消息属性结构体
typedef struct
{
char type; //'L'登录
char name[20]; //用户名
char text[128]; //信息内容
}msg_c;
void registe();
void login();
void chat();
int main(int argc, const char *argv[])
{
while(1)
{
printf("------------------------\n");
printf("------1.登录功能--------\n");
printf("------2.群聊功能--------\n");
printf("------3.下线功能--------\n");
printf("------4.接收数据--------\n");
printf("------------------------\n");
int menu;
printf("请输入功能:");
scanf("%d",&menu);
//对于选项多分支选择
switch(menu)
{
case 0:
{
//注册功能
registe();
}
break;
case 1:
{
//登录功能
login();
}
break;
case 2:
{
//群聊功能
chat();
}
break;
case 3:
{
//下线功能
exit(0);
}
break;
case 4:
{
//接收数据
}
break;
default:printf("输入功能错误,请重新输入字\n");
}
}
return 0;
}
/********************交互信息****************************/
void chat()
{
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return ;
}
printf("socket create success cfd=%d\n",cfd);
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(6666);
cin.sin_addr.s_addr = inet_addr("192.168.1.5");
if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) < 0)
{
ERR_MSG("bind");
return ;
}
printf("client bind success\n");
//填充服务器地址信息结构体,给sendto函数使用
//真实的地址信息结构体根据指定地址组指定,AF_INEF;
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(SET_PORT);//服务器端口
sin.sin_addr.s_addr =inet_addr(SET_IP);
char buf[128] = "";
struct sockaddr_in rcvaddr; //存储发送方的地址信息;
socklen_t addrlen = sizeof(sin);
while(1)
{
bzero(buf, sizeof(buf));
//发送数据----->从终端获取数据发送给指定端
printf("请输入>>");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return ;
}
printf("sendto success\n");
if(strcmp(buf,"quit")==0)
{
printf("返回菜单栏\n");
sleep(1);
break;
}
bzero(buf, sizeof(buf));
/* if(recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen) < 0)
{
ERR_MSG("recv");
return ;
}
*/ printf("__%d__",__LINE__);
}
}
/************************注册功能*******************************/
void registe()
{
char zczh[20]; //注册帐号
char zcmm[20]; //注册密码
printf("请输入注册帐号:");
scanf("%s",zczh);
printf("请输入注册密码:");
scanf("%s",zcmm);
//将注册帐号和注册密码写入文件中
FILE* zh_fd;
if((zh_fd=fopen("./password.txt","a"))==NULL)
{
ERR_MSG("open");
return;
}
//将帐号和密码写入文件中
fprintf(zh_fd,"%s %s\n",zczh,zcmm);
//关闭文件
fclose(zh_fd);
printf("注册成功\n");
}
/************************登录功能********************************/
void login()
{
char dlzh[20]; //登录帐号
char dlmm[20]; //登录密码
printf("请输入登录帐号:");
scanf("%s",dlzh);
printf("请输入登录密码:");
scanf("%s",dlmm);
//打开文件
FILE *zh_fd;
if((zh_fd=fopen("./password.txt","r"))==NULL)
{
ERR_MSG("open");
return ;
}
char userName[20];
char pwd[20];
while(1)
{
//从文件中读取数据
int ret=fscanf(zh_fd,"%s %s",userName,pwd);
if(ret <0)
{
printf("登录失败\n");
sleep(1);
printf("请重新登录\n");
return;
}
if(strcmp(userName,dlzh)==0&&strcmp(pwd,dlmm)==0)
{
printf("登录成功\n");
return;
}
}
}