服务器
主函数
#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<fcntl.h>
#include<linux/input.h>
#include<stdlib.h>
#include<pthread.h>
#include"server.h"
int sfd;
void* xc(void* arg)
{
char buf[128];
char chat[128];
while(1)
{
linklist *p=(linklist*)arg; //线程接收传过来的链表头节点地址
bzero(buf,sizeof(buf));
bzero(chat,sizeof(chat));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
p=p->next;
strcat(chat,"[server] : ");
strcat(chat,buf);
while(p != NULL)
{
socklen_t len = sizeof(p->cin);
if(sendto(sfd,chat,sizeof(chat),0,(struct sockaddr*)&(p->cin),len) < 0)
{
MSG_ERR("sendto");
return NULL;
}
p = p->next;
}
if(strcasecmp(buf,"quit") == 0) //服务器输入quit,直接关闭服务器并踢出所有人
{
printf("server have quit\n");
exit(0);
}
}
pthread_exit(0);
}
int main(int argc,const char* argv[])
{
sfd = socket(AF_INET,SOCK_DGRAM,0); //创建套接字
if(sfd < 0)
{
MSG_ERR("socket");
return -1;
}
printf("create socket success\n");
int reuse = 1; //端口能够复用
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
{
MSG_ERR("setsockopt");
return -1;
}
linklist *L=node_buy(); //申请链表
L->len=0;
L->next=NULL;
L->cin.sin_family = AF_INET; //将服务器的接口和IP地址存入链表头节点
L->cin.sin_port = htons(8888);
L->cin.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len = sizeof(L->cin);
if(bind(sfd,(struct sockaddr*)&(L->cin),len) < 0) //绑定服务器的接口和IP
{
MSG_ERR("bind");
return -1;
}
printf("bind success\n");
char buf[128]="";
pthread_t tid;
linklist *h=L;
if(pthread_create(&tid,NULL,xc,(void*)h) < 0) //创建线程
{
MSG_ERR("pthread_create");
return -1;
}
while(1)
{
bzero(buf,sizeof(buf));
linklist *p=node_buy();
socklen_t addrlen = sizeof(p->cin);
if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&p->cin,&addrlen) < 0) //创建一个新节点并将recvfrom函数收到客户端的接口和地址存入新节点里面
{
MSG_ERR("recvfrom");
return -1;
}
linklist *q=search(L,p); //寻找是否有相同的客户端
if(q!=NULL)
{
if(msgsend(L,q,p,buf,sfd) == -1) //有相同客户端就将该客户端的内容发送给其他客户端
{
printf("msgsend wrong\n");
return -1;
}
}
else
{
if(membersert(L,p,buf,sfd) == -1) //没有则表示客户端第一次输入,并且输入的是他的ID
{
printf("membersert wrong\n");
return -1;
}
}
}
pthread_join(tid,NULL);
close(sfd);
return 0;
}
.h文件
#ifndef __server_h__
#define __server_h__
#define MSG_ERR(msg) do{fprintf(stderr,"_%d_",__LINE__);perror(msg);}while(0)
typedef struct Node //创建的链表结构体
{
struct sockaddr_in cin;
union
{
int len;
char ID[20];
};
struct Node* next;
}linklist;
linklist *node_buy(); //节点申请函数
linklist *search(linklist *L,linklist *p); //寻找相同客户端函数
int msgsend(linklist *L,linklist *q,linklist *p,char buf[],int sfd); //传递客户端消息函数
int membersert(linklist *L,linklist *p,char buf[],int sfd); //存储新加入的客户端函数
#endif
.c文件
#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<fcntl.h>
#include<linux/input.h>
#include<stdlib.h>
#include<pthread.h>
#include"server.h"
linklist *node_buy()
{
linklist *p = (linklist*)malloc(sizeof(linklist));
if(NULL == p)
{
printf("apply failed\n");
return NULL;
}
return p;
}
linklist *search(linklist *L,linklist *p)
{
linklist *q=L->next;
while(q!=NULL)
{
if(q->cin.sin_port == p->cin.sin_port) //遍历链表,如果有相同接口号,说明该客户端已经存入过
{
return q;
break;
}
q=q->next;
}
return NULL;
}
int msgsend(linklist *L,linklist *q,linklist *p,char buf[],int sfd)
{
char chat[128]="";
bzero(chat,sizeof(chat));
linklist *h=L;
int sig=0;
if(strcasecmp(buf,"quit") == 0) //如果客户端输入了quit,则表示退出
{
strcat(chat,"-----");
strcat(chat,q->ID);
strcat(chat," have quit-----");
printf("%s\n",chat);
while(h->next->cin.sin_port != p->cin.sin_port)
{
h=h->next;
}
sig=1;
}
else //否则表示客户端在发送内容
{
strcat(chat,"[client]:");
strcat(chat,q->ID);
strcat(chat," : ");
strcat(chat,buf);
}
if(sig == 1) //删除退出的客户端节点
{
h->next = q->next;
free(q);
q=NULL;
}
linklist *l = L->next;
socklen_t len=sizeof(l->cin);
while(l != NULL)
{
if(l->cin.sin_port == p->cin.sin_port)
{
l=l->next;
continue;
}
if(sendto(sfd,chat,sizeof(chat),0,(struct sockaddr*)&l->cin,len) < 0)
{
MSG_ERR("sendto");
return -1;
}
l=l->next;
}
return 0;
}
int membersert(linklist *L,linklist *p,char buf[],int sfd)
{
strcpy(p->ID,buf);
p->next = L->next;
L->next = p;
L->len++;
linklist *h = L->next;
char chat[128]="";
strcat(chat,"-----");
strcat(chat,buf);
strcat(chat," join the chat-----");
printf("%s\n",chat);
socklen_t len=sizeof(h->cin);
while(h != NULL)
{
if(h->cin.sin_port == p->cin.sin_port)
{
h=h->next;
continue;
}
if(sendto(sfd,chat,sizeof(chat),0,(struct sockaddr*)&h->cin,len) < 0)
{
MSG_ERR("sendto");
return -1;
}
h=h->next;
}
}
客户端
#include<linux/input.h>
#include<pthread.h>
#include<stdlib.h>
#define MSG_ERR(msg) do{fprintf(stderr,"_%d_",__LINE__);perror(msg);}while(0)
void* xc(void* arg)
{
int sfd=*(int*)arg;
char buf[128]="";
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while(1)
{
bzero(buf,sizeof(buf));
if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen) < 0)
{
MSG_ERR("recvfrom");
return NULL;
}
printf("%s\n",buf);
if(strcasecmp(buf,"[server] : quit") == 0)
{
exit(0);
}
}
pthread_exit(0);
}
int main(int argc,const char* argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd < 0)
{
MSG_ERR("socket");
return -1;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr(argv[1]);
char buf[128];
char name[128];
printf("Enter your ID>>> ");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
strcpy(name,buf);
if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
MSG_ERR("sendto");
return -1;
}
pthread_t tid;
if(pthread_create(&tid,NULL,xc,(void*)&sfd) < 0)
{
MSG_ERR("pthread_create");
return -1;
}
while(1)
{
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
MSG_ERR("sendto");
return -1;
}
if(strcasecmp(buf,"quit") == 0)
{
printf("you have quit\n");
exit(0);
}
}
pthread_join(tid,NULL);
close(sfd);
return 0;
}
测试结果
服务器
客户端1
客户端2