1.
需求
项目需求:
1.
如果有用户登录,其他用户可以收到这个人的登录信息
2.
如果有人发送信息,其他用户可以收到这个人的群聊信息
3.
如果有人下线,其他用户可以收到这个人的下线信息
4.
服务器可以发送系统信息
服务器端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct sockaddr_in IN;
typedef struct Node1
{
char name[20];
char msg1[128];
int S;
}msg;
int len_msg =sizeof(msg);
int len_addr=sizeof(struct sockaddr_in);
typedef struct user_list
{
struct sockaddr_in cin;
struct user_list *next;
}Linklist;
IN ser_addr,cli_addr;
Linklist* list;
//打印错误新的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr, " __%d__ ", __LINE__);\
perror(msg);\
}while(0)
//初始化链表
void init();
//尾插
void insert_tail(IN cin);
void* thread_user(void *arg );
//删除用户
void list_delete(IN cin);
void user_log(int sfd,msg msg_user, IN cli_addr); //用户登录
void user_send(int sfd,msg msg_user,IN cli_addr); //用户发送消息
void user_quit(int sfd,msg msg_user,IN cli_addr); //用户退出
void ser_send(int sfd,char *buf); //服务端发送给用户
//初始化链表
void init()
{
list=(Linklist*)malloc(sizeof(Linklist));
list->next=NULL;
// printf("创建成功\n");
}
//尾插
void insert_tail(IN cin )
{
Linklist *q=list;
int i=1;
while(q->next !=NULL)
{
q=q->next;
}
Linklist *qq=(Linklist*)malloc(sizeof(cin));
qq->cin=cin;
qq->next=q->next;
q->next=qq;
}
//删除用户
void list_delete(IN cin)
{
Linklist *p=list->next;
Linklist *q=list;
int i=1;
while(p!=NULL && p->next!=NULL)
{
if(p->cin.sin_port ==cin.sin_port &&p->cin.sin_addr.s_addr ==cli_addr.sin_addr.s_addr)
break;
p=p->next;
q=q->next;
}
q->next=p->next;
free(p);
}
void user_log(int sfd,msg msg_user,IN cli_addr) //用户登录
{
char buf[128]="";
Linklist* P=list->next;
char name1[30]={0};
strcat(name1,msg_user.name);
strcat(name1,"登录\n");
printf("%s",name1);
while(P)
{
sendto(sfd,name1,strlen(name1),0,(struct sockaddr*)&P->cin,len_addr);
P=P->next;
}
insert_tail(cli_addr);
}
void user_send(int sfd,msg msg_user,IN cli_addr) //用户发送消息
{
char buf[128]="";
Linklist* P=list->next;
strcat(buf,msg_user.name);
strcat(buf," send: ");
strcat(buf,msg_user.msg1); //将信息打包进buf
buf[strlen(buf)]='\0';
printf("%s",msg_user.msg1);
//发送给别的客户端
while(P)
{
//判断是不是用户本身
if((P->cin.sin_port !=cli_addr.sin_port) ||(P->cin.sin_addr.s_addr != cli_addr.sin_addr.s_addr) )
{
sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(P->cin),len_addr);
}
P=P->next;
}
}
void user_quit(int sfd,msg msg_user,IN cli_addr) //用户退出
{
Linklist *P=list->next;
char buf[128]="";
strcat(buf,msg_user.name);
strcat(buf,"退出\n");
printf("%s",buf);
while(P)
{
sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(P->cin),len_addr);
P=P->next;
}
list_delete(cli_addr);
//ser_send(sfd,buf);
}
void ser_send(int sfd,char *buf) //服务端发送给用户
{
Linklist *P=list->next;
while(P)
{
sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&P->cin,len_addr);
P=P->next;
}
}
//子线程,存储用户的信息地址结构体
void* thread_user(void *arg )
{
int sfd=*(int *)arg;
while(1)
{
msg msg_user;
int len_msg=sizeof(msg_user);
//接收用户端的信息,保存在结点中
int res=recvfrom(sfd,&msg_user,sizeof(msg_user),0,(struct sockaddr*)&cli_addr,&len_addr);
if(res < 0)
{
perror("recvfrom");
exit(0);
}
//printf("%s:",msg_user.name);
switch(msg_user.S)
{
case 1:
user_log(sfd,msg_user,cli_addr); //用户登录
break;
case 2:
printf("%s:",msg_user.name);
user_send(sfd,msg_user,cli_addr); //用户发送消息
break;
case 3:
user_quit(sfd,msg_user,cli_addr); //用户退出
break;
}
}
}
int main(int argc, const char *argv[])
{
if(argc < 3)
{
fprintf(stderr, "请输入IP port\n");
return -1;
}
init();
//将获取到的端口号字符串,转换成整形
int port = atoi(argv[2]);
if(port < 1024 || port > 49151)
{
fprintf(stderr, "port %d input error!! 1024~49151\n", port);
return -1;
}
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//填充服务器的IP地址以及端口号
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(atoi(argv[2]));
sin.sin_addr.s_addr = inet_addr(argv[1]);
pthread_t thread;
//绑定服务器的地址信息结构体
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success\n");
pthread_create(&thread,NULL,thread_user,&sfd);
while(1)
{
char buf[140]="";
char msg1[128]="";
bzero(buf,sizeof(buf));
bzero(msg1,sizeof(msg1));
strcat(buf,"系统:");
fgets(msg1,128,stdin);
strcat(buf,msg1);
ser_send(sfd,buf);
}
//关闭套接字
close(sfd);
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
int sfd=0;
typedef struct sockaddr_in IN;
typedef struct
{
char name[20];
char msg1[128];
int S;
}msg;
//打印错误新的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr, " __%d__ ", __LINE__);\
perror(msg);\
}while(0)
void* recv1(void* arg)
{
pthread_detach(pthread_self());
IN cin;
char buf[140]="";
int addrlen=sizeof(cin);
while(1)
{
char buf[140]="";
//接收服务器发送过来的数据包
recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cin, &addrlen);
if(strcmp(buf,"quit")==0)
{
exit(0);
}
printf("%s", buf);
}
}
int main(int argc, const char *argv[])
{
if(argc < 3)
{
fprintf(stderr, "请输入IP port\n");
return -1;
}
msg msg_user;
//将获取到的端口号字符串,转换成整形
int port = atoi(argv[2]);
if(port < 1024 || port > 49151)
{
fprintf(stderr, "port %d input error!! 1024~49151\n", port);
return -1;
}
//int addrlen= sizeof(cin);
//创建报式套接字
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//填充客户端的IP地址以及端口号 -->因为客户端要主动发送数据包给服务器
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(6666);
cin.sin_addr.s_addr = inet_addr(argv[1]);
//绑定客户端自身的地址信息结构体
/* if(bind(sfd,(struct sockaddr*)&cin,sizeof(cin))<0)
{
ERR_MSG("bind");
return -1;
}
*/
//填充服务器的IP地址以及端口号 -->因为客户端要主动发送数据包给服务器
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(atoi(argv[2]));
sin.sin_addr.s_addr = inet_addr(argv[1]);
//登录信息输入
char name[20];
printf("输入你用户名>>>");
fgets(name,20,stdin);
name[strlen(name)-1]='\0';
strcpy(msg_user.name,name);
msg_user.S=1;
sendto(sfd,&msg_user,sizeof(msg_user),0,(struct sockaddr*)&sin,sizeof(sin));
pthread_t tid;
if(pthread_create(&tid,NULL,recv1,(void*)&sin)<0)
{
ERR_MSG("pthread_create");
return -1;
}
//发送消息
char sendmsg[128]="";
while(1)
{ //输入信息
bzero(sendmsg,sizeof(sendmsg));
fgets(sendmsg,128,stdin);
strcpy(msg_user.name,name);
strcpy(msg_user.msg1,sendmsg);
//如果遇到quit\n退出
if(strcmp(sendmsg,"quit\n")==0)
{
msg_user.S=3;
if(sendto(sfd,&msg_user,sizeof(msg_user),0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
perror("sento");
exit(0);
}
exit(0);
}
else
{
msg_user.S=2;
}
//发送到服务端
if(sendto(sfd,&msg_user,sizeof(msg_user),0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
perror("sento");
exit(0);
}
// waitpid(-1, NULL, WNOHANG);
}
close(sfd);
return 0;
}