服务器
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#define send_port "8888"
#define send_ip "192.168.1.6"
//存储用户端信息
typedef struct user{
struct sockaddr_in user;
struct user* next;
struct user* prve;
}USER;
//创建链表
USER* creat_link(void){
USER* head=(USER*)malloc(sizeof(struct user));
head->next=NULL;
head->prve=NULL;
memset(&(head->user),0,sizeof(head->user));
return head;
}
//新用户上线
void add_link(USER* head,struct sockaddr_in usr){
USER* uhead=(USER*)malloc(sizeof(USER));
uhead->next=head->next;
uhead->prve=head;
uhead->user=usr;
head->next=uhead;
return ;
}
//用户下线
void delete_link(USER* head){
USER* temp =NULL;
temp=head->prve;
temp->next=head->next;
head->next->prve=temp;
free(head);
return ;
}
int main(int argc, const char *argv[])
{
//创建链表
USER* head=creat_link();
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0){
perror("socket");
return -1;
}
int optval=1;
int spt=setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void *)&optval,sizeof(optval));
if(spt<0){
perror("setsockopt");
return -1;
}
//绑定广播地址
struct sockaddr_in bro_addr;
memset(&bro_addr,0,sizeof(bro_addr));
bro_addr.sin_family=AF_INET;
bro_addr.sin_port=htons(atoi(send_port));
bro_addr.sin_addr.s_addr=inet_addr(send_ip);
memset(bro_addr.sin_zero,0,sizeof(bro_addr.sin_zero));
int bindflag=bind(sockfd,(struct sockaddr*)&bro_addr,sizeof(bro_addr));
if(bindflag<0){
perror("bind");
return -1;
}
//创建子进程
//int key=0;
int pfd[2]={0};
if(pipe(pfd)<0){
perror("pipe");
return -1;
}
printf("无名管道创建成功\n");
pid_t pid=fork();
if(pid>0){ //父进程
while(1){
ssize_t res=0;
USER* temp;
res=read(pfd[0],temp,sizeof(temp));
if(res<0){
perror("read");
return -1;
}
USER* p=(temp)->next;
while(p!=NULL){
printf("%d\n",__LINE__);
char send_buf[1024];
memset(send_buf,0,sizeof(send_buf));
ssize_t res=0;
res=read(pfd[0],send_buf,sizeof(send_buf));
if(res<0){
perror("read");
return -1;
}
int sendflag=sendto(sockfd,send_buf,sizeof(send_buf),0,(struct sockaddr*)&(p->user),sizeof(p->user));
if(sendflag<0){
perror("sendto");
return -1;
}
}
}
}
/*子进程
* 实现客户端的查询是否有客户端上线
* 已上线的客户端,进行数据传输
* 判断是否有客户端用户要退出
* */
else if(0==pid){
while(1){
char recv_buf[1024];//定义字符串,用于接收数据
memset(recv_buf,0,sizeof(recv_buf));//将字符串清空
struct sockaddr_in recv_addr;//定义一个结构体变量,用于接收IP和端口号
memset(&recv_addr,0,sizeof(recv_addr));//清空结构体
socklen_t len=sizeof(recv_buf);//计算字符串的大小
int recvflag=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&recv_addr,&len);//接收数据
if(recvflag<0)//判断接收数据是否成功
{
printf("recvfrom error!\r\n");
return -4;
}
USER* p=head;//创建一个链表节点
int k=0;
while(p->next!=NULL){
p=p->next;
in_port_t port=p->user.sin_port;
if(port==recv_addr.sin_port){
int i=strcmp(recv_buf,"quit");
if(i==0){
delete_link(p);
p=NULL;
k=1;
break;
}
USER** phead=head;
if(write(pfd[1],phead,sizeof(phead))<0){
perror("地址_write");
return -1;
}
if(write(pfd[1],recv_buf,sizeof(recv_buf))<0){
perror("write");
return -1;
}
printf("IP:%s PORT:%d data:%s\n",\
inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),recv_buf);
k=1;
}
}
if(p->next==NULL&&0==k){
add_link(p,recv_addr);
printf("IP:%s PORT:%d上线\n",\
inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port));
}
}
}
else{
perror("fork");
return -1;
}
//printf("数据发送完成:%s\n",recv_buf);
close(sockfd);
return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#define send_port "8888"
#define send_ip "192.168.1.6"
int main(int argc, const char *argv[])
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0){
perror("socket");
return -1;
}
int optval=1;
int spt=setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void *)&optval,sizeof(optval));
if(spt<0){
perror("setsockopt");
return -1;
}
struct sockaddr_in send_addr;
memset(&send_addr,0,sizeof(send_addr));
send_addr.sin_family=AF_INET;
send_addr.sin_port=htons(atoi(send_port));
send_addr.sin_addr.s_addr=inet_addr(send_ip);
memset(send_addr.sin_zero,0,sizeof(send_addr));
char buf[64];
memset(buf,0,sizeof(buf));
//fgets(buf,sizeof(buf),stdin);
//buf[strlen(buf)-1]='\0';
ssize_t buf_len= sizeof(buf);
if(sendto(sockfd,buf,buf_len,0,(struct sockaddr*)&send_addr,sizeof(send_addr))<0){
perror("sendto");
return -1;
}
int pfd[2]={0};
if(pipe(pfd)<0){
perror("pipe");
return-1;
}
pid_t pid=fork();
if(pid>0){
while(1){
char buf[64];
memset(buf,0,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';
ssize_t buf_len= sizeof(buf);
if(sendto(sockfd,buf,buf_len,0,(struct sockaddr*)&send_addr,sizeof(send_addr))<0){
perror("sendto");
return -1;
}
if(strcmp(buf,"quit")==0){
if(write(pfd[1],buf,sizeof(buf))<0){
perror("write");
return -1;
}
printf("退出群聊\n");
pid_t id=wait(NULL);
break;
}
}
}
else if(pid==0){
while(1){
ssize_t res=0;
char bufc[1024];
res=read(pfd[0],bufc,sizeof(bufc));
if(res<0){
perror("read");
return -1;
}
if(strcmp(bufc,"quit")==0){
exit(0);
}
char recv_buf[1024];//定义字符串,用于接收数据
memset(recv_buf,0,sizeof(recv_buf));//将字符串清空
struct sockaddr_in recv_addr;//定义一个结构体变量,用于接收IP和端口号
memset(&recv_addr,0,sizeof(recv_addr));//清空结构体
socklen_t len=sizeof(recv_buf);//计算字符串的大小
int recvflag=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&recv_addr,&len);
if(recvflag<0)//判断接收数据是否成功
{
printf("recvfrom error!\r\n");
return -4;
}
printf("IP:%s PORT:%d data:%s\n",\
inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),recv_buf);
}
}else{
perror("fork");
return -1;
}
printf("数据发送完成\n");
close(sockfd);
return 0;
}