服务器
#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>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0);
typedef struct
{
char name[20];
char msg[128];
int flag;
}INFO;
typedef struct Node
{
struct sockaddr_in usr;
struct Node *next;
}Linklist;
int sfd;
struct sockaddr_in clnt_addr;
struct sockaddr_in serv_addr;
socklen_t addrlen=sizeof(struct sockaddr_in);
Linklist *list_create()
{
Linklist *L=(Linklist*)malloc(sizeof(Linklist));
L->next=NULL;
return L;
}
void login_insert(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
Linklist *q=L->next;
//遍历群发登录信息
char buf[20]="";
strcpy(buf,info.name);
strcat(buf,"已登录...\n");
while(q!=NULL)
{
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),addrlen);
q=q->next;
}
//头插
Linklist *p =(Linklist*)malloc(sizeof(Linklist));
if(NULL==p)
{
printf("节点申请失败\n");
exit(0);
}
p->usr=clnt_addr;
p->next=NULL;
p->next=L->next;
L->next=p;
}
void send_msg(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
Linklist *q=L->next;
char buf[200]="";
strcat(buf,info.name);
strcat(buf,":");
strcat(buf,info.msg);
buf[strlen(buf)]=0;
while(q!=NULL)
{
sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(q->usr),addrlen);
q=q->next;
}
}
void send_off(Linklist *L,int sfd,INFO info,struct sockaddr_in clnt_addr)
{
Linklist *q=L->next;
char buf[200]="";
strcat(buf,info.name);
strcat(buf,"已下线\n");
while(q!=NULL)
{
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),addrlen);
q=q->next;
}
q=L->next;
while(q->next!=NULL)
{
if(q->usr.sin_port == clnt_addr.sin_port && (q->usr.sin_addr.s_addr & clnt_addr.sin_addr.s_addr) == clnt_addr.sin_addr.s_addr)break;
q=q->next;
}
Linklist *p=q->next;
q->next=p->next;
free(p);
p=NULL;
}
void* func(void* arg)
{
Linklist *L=(Linklist*)arg;
while(1)
{
INFO info;
if(recvfrom(sfd,&info,sizeof(info),0,(struct sockaddr*)&clnt_addr,&addrlen)<0)
{
ERR_MSG("recvfrom");
exit(0);
}
printf("recv success\n");
switch(info.flag)
{
case 1:
{
printf("[%s]已登录!\n",info.name);
login_insert(L,sfd,info,clnt_addr);break;}
case 2:
{send_msg(L,sfd,info,clnt_addr);break;}
case 3:
{send_off(L,sfd,info,clnt_addr);break;}
}
}
}
int main(int argc, const char *argv[])
{
if(argc<3)
{
fprintf(stderr,"请输入IP port\n");
return -1;
}
//将获取到的端口号字符串,转换成整形
int port =atoi(argv[2]);
if(port<1024 || port > 49151)
{
fprintf(stderr,"port %d input error !! 1024~49151\n",port);
return -1;
}
//创建报式套接字
sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
//填充服务器的IP地址以及端口号
serv_addr.sin_family =AF_INET;
serv_addr.sin_port =htons(port);
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
//绑定服务器的地址信息结构体
if(bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success\n");
Linklist *L=list_create();
//创建线程
pthread_t tid;
if(pthread_create(&tid,NULL,func,(void*)L)!=0)
{
perror("pthread_create");
return -1;
}
while(1)
{
char buf[128]="";
char msg[64]="";
strcat(buf,"**system**");
fgets(msg,48,stdin);
strcat(buf,msg);
Linklist *q=L->next;
while(q!=NULL)
{
if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(q->usr),(sizeof(struct sockaddr_in)))<0)
{
ERR_MSG("sendto");
exit(0);
}
q=q->next;
}
}
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>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0);
typedef struct
{
char name[20];
char msg[128];
int flag;
}INFO;
INFO info;
void *func(void *arg)
{
pthread_detach(pthread_self());
int sfd=*(int*)arg;
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
char buf[200]="";
while(1)
{
bzero(buf,sizeof(buf));
if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen)<0)
{
ERR_MSG("recvfrom");
break;
}
printf("\n");
printf("%s\n",buf);
printf("请输入>>>");
fflush(stdout);
}
}
int main(int argc, const char *argv[])
{
if(argc<3)
{
fprintf(stderr,"请输入IP port\n");
return -1;
}
//将获取到的端口号字符串,转换成整形
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(port);
sin.sin_addr.s_addr=inet_addr(argv[1]);
struct sockaddr_in rcv_addrmsg;
socklen_t addrlen=sizeof(rcv_addrmsg);
//绑定服务器的地址信息结构体-->非必须绑定
printf("请输入姓名>>>");
fgets(info.name,sizeof(info.name),stdin);
info.name[strlen(info.name)-1]=0;
info.flag=1;
if(sendto(sfd,&info,sizeof(info),0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
//创建线程
pthread_t tid;
if(pthread_create(&tid,NULL,func,(void *)&sfd)!=0)
{
perror("pthread_create");
return -1;
}
char name[20];
strcpy(name,info.name);
while(1)
{
INFO info;
strcpy(info.name,name);
bzero(info.msg,sizeof(info.msg));
printf("请输入>>>");
fgets(info.msg,sizeof(info.msg),stdin);
info.msg[strlen(info.msg)-1]=0;
if(strcmp(info.msg,"exit")==0)
{
info.flag=3;
printf("已下线\n");
}else
info.flag=2;
if(sendto(sfd,&info,sizeof(info),0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("sendto");
exit(0);
}
printf("sendto success\n");
if(info.flag==3)
exit(0);
}
return 0;
}