项目需求:
1.如果有用户登录,其他用户可以收到这个人的登录信息
2.如果有人发送信息,其他用户可以收到这个人的群聊信息
3.如果有人下线,其他用户可以收到这个人的下线信息
4.服务器可以发送系统信息
udp服务器代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\n",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.8.18"
#define PORT 6666
typedef struct Node
{
union {
int len;
struct sockaddr_in cin ;
};
struct Node * next;
}LinkList;
struct mg
{
char num;
char name[20];
char text[200];
};
struct sockaddr_in cin;
char buf[128]="";
ssize_t res = 0;
LinkList *L;
int sfd;
socklen_t addrlen =sizeof(cin);
struct mg std,std1;
LinkList *q;
LinkList *list_create ()
{
//申请一个结点
LinkList *L=(LinkList*)malloc(sizeof(LinkList));
if(NULL==L)
{
printf("创建失败\n");
return NULL;
}
//创建成功进行初始化
L->len=0;
L->next =NULL;
printf("创建成功\n");
return L;
}
//申请结点封装数据函数
LinkList *buy_nobe(struct sockaddr_in e)
{
//在堆区申请一个结点空间
LinkList *p = (LinkList*)malloc(sizeof(LinkList));
if(NULL==p)
{
printf("空间申请失败\n");
return NULL;
}
//将数据封装到结点的数据域中
p->cin=e;
p->next=NULL;
return p;
}
int list_empty(LinkList *L)
{
return L->next==NULL ? 1:0; //1表示空,0表示非空
}
//头插
int list_inset_head(LinkList* L,struct sockaddr_in e)
{
//判断逻辑
if(NULL == L)
{
printf("所给链表不合法\n");
return -1;
}
//申请结点封装数据
LinkList *p = buy_nobe(e);
//头插逻辑
p->next=L->next;
L->next=p;
//表的变化
L->len++;
}
//按值进行查找
int list_search_value(LinkList *L,struct sockaddr_in e)
{
//判断逻辑
if(NULL==L || list_empty(L))
{
printf("查找失败\n");
return -1;
}
//查找逻辑
LinkList *q = L->next; //从第一个结点出发
for(int i=1;i<=L->len;i++)
{
if(memcmp(&q->cin,&e,sizeof(e))==0)
{
return i;
}
q=q->next; //继续判断下一个结点
}
return 0; //说明,没有找到
}
//按位置查找返回结点
LinkList* find_node(LinkList *L,int pos)
{
//判断逻辑
if(pos<0||pos>L->len)
{
printf("查找失败\n");
return NULL;
}
//查找逻辑
//定义遍历指针从头结点出发
LinkList *q = L;
for(int i=0; i<pos; i++)
{
q = q->next; //遍历指针往后移
}
return q; // 将找到的结点返回
}
//任意位置删除
int list_delete_pos(LinkList *L,int pos)
{
//判断逻辑
if(NULL==L|| list_empty(L) ||pos<1 || pos>L->len)
{
printf("删除失败\n");
return 0;
}
//找到想要删除的结点的前驱结点
LinkList *q =find_node(L,pos-1);
if(q==NULL)
{
printf("删除失败\n");
return 0;
}
//删除逻辑
LinkList *p = q->next;
q->next = p->next;
free(p);
p=NULL;
//表长变化
L->len--;
return 1;
}
void *recvA(void *arg)
{
while(1)
{
res=recvfrom(sfd,&std,sizeof(std),0,(struct sockaddr*)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
}
if(std.num=='L')
{
printf("%s已上线\n",std.name);
strcat(std.name,"已上线");
LinkList*q=L->next;
while(q!=NULL)
{
if(sendto(sfd,&std,sizeof(std.name),0,(struct sockaddr*)&(q->cin),sizeof(cin))<0)
{
ERR_MSG("sendto");
}
q=q->next;
}
list_inset_head(L,cin);
}
if(std.num=='C')
{
printf("%s:%s\n",std.name,std.text);
LinkList *q=L->next;
while(q!=NULL)
{
if(memcmp(&q->cin,&cin,sizeof(cin))!=0)
{
if(sendto(sfd,&std,sizeof(std.text),0,(struct sockaddr*)&(q->cin),sizeof(cin))<0)
{
ERR_MSG("sendto");
}
}
q=q->next;
}
}
if(std.num=='Q')
{
printf("%s:%s\n",std.name,std.text);
LinkList *q=L->next;
while(q!=NULL)
{
if(memcmp(&q->cin,&cin,sizeof(cin))!=0)
{
if(sendto(sfd,&std,sizeof(std.text),0,(struct sockaddr*)&(q->cin),sizeof(cin))<0)
{
ERR_MSG("sendto");
}
}
else
{
int pos;
pos=list_search_value(L,cin);
list_delete_pos(L,pos);
}
q=q->next;
}
}
}
}
void *sendB(void *arg)
{
while(1)
{
bzero(&std1,sizeof(std));
strcpy(std1.name,"system");
char str[200];
scanf("%s",str);
strcpy(std1.text,str);
q=L->next;
while(q!=NULL)
{
if(sendto(sfd,&std1,sizeof(std.text),0,(struct sockaddr*)&(q->cin),sizeof(cin))<0)
{
ERR_MSG("sendto");
}
q=q->next;
}
}
}
int main(int argc, const char *argv[])
{
L=list_create();
if(L==NULL)
{
printf("list_create fail\n");
return -1;
}
sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) <0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速重用成功\n");
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(PORT);
sin.sin_addr.s_addr =inet_addr(IP);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success\n");
char buf[128]="";
ssize_t res = 0;
socklen_t addrlen =sizeof(cin);
pthread_t tid1,tid2;
if((pthread_create(&tid1,NULL,recvA,NULL))<0)
{
ERR_MSG("tid1");
return -1;
}
if((pthread_create(&tid2,NULL,sendB,NULL))<0)
{
ERR_MSG("tid1");
return -1;
}
pthread_join(tid1,NULL);
close(sfd);
return 0;
}
udp客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\n",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.8.18"
#define PORT 6666
char buf[128]="";
ssize_t res = 0;
int sfd;
struct mg
{
char num;
char name[20];
char text[200];
};
void *sendA(void *arg)
{
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(PORT);
sin.sin_addr.s_addr =inet_addr(IP);
struct sockaddr_in send;
send.sin_family =AF_INET;
send.sin_port =htons(PORT);
send.sin_addr.s_addr =inet_addr(IP);
struct mg std;
bzero(buf,sizeof(buf));
std.num ='L';
printf("登录请输入姓名>>>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
strcpy(std.name,buf);
if(sendto(sfd,&std,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("sendto");
}
printf("sendto success\n");
int size=sizeof(buf);
while(1)
{
std.num='C';
char str[5000];
bzero(std.text,sizeof(std.text));
scanf("%s",str);
if(strcmp(str,"quit")==0)
{
std.num='Q';
strcpy(std.text,"已下线");
if(sendto(sfd,&std,sizeof(std.text),0,(struct sockaddr*)&send,sizeof(send))<0)
{
ERR_MSG("sendto");
}
printf("sendto success\n");
break;
}
else
{
strcpy(std.text,str);
if(sendto(sfd,&std,sizeof(std.text),0,(struct sockaddr*)&send,sizeof(send))<0)
{
ERR_MSG("sendto");
}
printf("sendto success\n");
}
}
}
void *recvB(void*arg)
{
struct mg std;
struct sockaddr_in rcvAddr;
socklen_t addrlen =sizeof(rcvAddr);
while(1)
{
res=recvfrom(sfd,&std,sizeof(std),0,(struct sockaddr*)&rcvAddr,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
}
printf("%s:%s\n",std.name,std.text);
}
}
int main(int argc, const char *argv[])
{
sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
pthread_t tid1,tid2;
if(pthread_create(&tid1,NULL,sendA,NULL)<0)
{
ERR_MSG("tid1");
return -1;
}
if(pthread_create(&tid2,NULL,recvB,NULL)<0)
{
ERR_MSG("tid2");
return -1;
}
pthread_join(tid1,NULL);
close(sfd);
return 0;
}
项目实验结果:
![](https://i-blog.csdnimg.cn/blog_migrate/01ec0a0e1e7edbf65d76aefc6923419d.png)