基于UDP的网络聊天室运行结果功能:
登录:
![在这里插入图片描述](https://img-blog.csdnimg.cn/1285627dd07540da869ad8901aad26b8.png)
群聊:
![在这里插入图片描述](https://img-blog.csdnimg.cn/b63e010e4b934452b787f8bdde005b47.png)
服务器发消息:
![在这里插入图片描述](https://img-blog.csdnimg.cn/0b2935b6b6a944cc84adad098a4d4fe4.png)
下线:
![在这里插入图片描述](https://img-blog.csdnimg.cn/bf22ae7505264b04843299cfc97a026a.png)
代码
服务器:
#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",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.31.143"
#define PORT 5896
struct MSG
{
char type;
char name[20];
char text[128];
}msg;
typedef struct Node
{
int len;
struct sockaddr_in cin;
struct Node* next;
} * Linklist;
Linklist l;
void *deal_cli_msg(void *arg);
Linklist create_head();
Linklist create_node(struct sockaddr_in cin);
int insert_head(Linklist l,struct sockaddr_in cin);
int search_data(Linklist l,struct sockaddr_in cin);
int delete_pos(Linklist l,int pos);
int delete_head(Linklist l);
Linklist list_free(Linklist l);
int main(int argc, const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd < 0){
ERR_MSG("socket");
return -1;
}
printf("socket success\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("bing success\n");
ssize_t res = 0;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
l = create_head();
if(NULL == l){
return -1;
}
pthread_t tid;
if(pthread_create(&tid,NULL,deal_cli_msg,&sfd) != 0){
fprintf(stderr,"line:%d pthread_create failed\n",__LINE__);
}
while(1){
memset(msg.name,0,sizeof(msg.name));
memset(msg.text,0,sizeof(msg.text));
res = recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen);
if(res < 0){
ERR_MSG("recvfrom");
return -1;
}
if('L' == msg.type){
printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),msg.name);
insert_head(l,cin);
Linklist q = l;
for(int i=0; i<l->len; i++){
q = q->next;
if((q->cin.sin_port != cin.sin_port) &&(q->cin.sin_addr.s_addr == cin.sin_addr.s_addr)){
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(q->cin),sizeof(q->cin)) < 0){
ERR_MSG("sendto");
break;
}
}
}
}else if('C' == msg.type){
printf("[%s:%d]:%s:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),msg.name,msg.text);
Linklist q = l;
for(int i=0; i<l->len; i++){
q = q->next;
if((q->cin.sin_port != cin.sin_port) &&(q->cin.sin_addr.s_addr == cin.sin_addr.s_addr)){
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(q->cin),sizeof(q->cin)) < 0){
ERR_MSG("sendto");
break;
}
}
}
}else if('Q' == msg.type){
printf("%s下线\n",msg.name);
msg.type = 'Q';
Linklist q = l;
for(int i=0; i<l->len; i++){
q = q->next;
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(q->cin),sizeof(q->cin)) < 0){
ERR_MSG("sendto");
break;
}
}
int pos = search_data(l,cin);
delete_pos(l,pos);
}
}
l = list_free(l);
close(sfd);
return 0;
}
void *deal_cli_msg(void *arg)
{
pthread_detach(pthread_self());
int sfd = *(int *)arg;
struct MSG msg;
while(1){
msg.type = 'S';
memset(msg.text,0,sizeof(msg.text));
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text)-1] = '\0';
Linklist p = l;
for(int i=0; i<l->len; i++){
p = p->next;
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->cin),sizeof(p->cin)) < 0){
ERR_MSG("sendto");
break;
}
printf("__%d__\n",__LINE__);
}
}
}
Linklist create_head()
{
Linklist l = (Linklist)malloc(sizeof(struct Node));
if(NULL == l)
return NULL;
l->len = 0;
l->next = NULL;
return l;
}
Linklist create_node(struct sockaddr_in cin)
{
Linklist p = (Linklist)malloc(sizeof(struct Node));
if(NULL == p)
return NULL;
p->cin = cin;
p->next = NULL;
return p;
}
int insert_head(Linklist l,struct sockaddr_in cin)
{
if(NULL == l){
printf("插入失败\n");
return -1;
}
Linklist p = create_node(cin);
p->next = l->next;
l->next = p;
l->len++;
return 0;
}
int search_data(Linklist l,struct sockaddr_in cin)
{
if(NULL == l || 0 == l->next){
printf("查找失败\n");
return -1;
}
Linklist p = l;
int count = 0;
while(p->next != NULL){
p = p->next;
count++;
if((p->cin.sin_port == cin.sin_port) && (p->cin.sin_addr.s_addr == cin.sin_addr.s_addr)){
return count;
}
}
return 0;
}
int delete_pos(Linklist l,int pos)
{
if(NULL == l || 0 == l->len || pos < 1 || pos > l->len){
printf("删除失败\n");
return -1;
}
Linklist p = l;
for(int i=0; i<pos-1; i++){
p = p->next;
}
Linklist q = p->next;
p->next = q->next;
free(q);
q = NULL;
l->len--;
return 0;
}
int delete_head(Linklist l)
{
if(NULL == l || 0 == l->len){
printf("删除失败\n");
return -1;
}
Linklist q = l->next;
l->next = q->next;
free(q);
q = NULL;
l->len--;
return 0;
}
Linklist list_free(Linklist l)
{
if(NULL == l){
return NULL;
}
int n = l->len;
for(int i=0; i<n; i++){
delete_head(l);
}
free(l);
l = NULL;
return l;
}
客户端
#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",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.31.143"
#define PORT 5896
struct MSG
{
char type;
char name[20];
char text[128];
};
struct Node
{
struct sockaddr_in sin;
int cfd;
struct MSG msg;
};
void *deal_cli_msg(void *arg);
int main(int argc, const char *argv[])
{
struct Node value;
value.cfd = socket(AF_INET,SOCK_DGRAM,0);
if(value.cfd < 0){
ERR_MSG("socket");
return -1;
}
printf("socket success\n");
value.sin.sin_family = AF_INET;
value.sin.sin_port = htons(PORT);
value.sin.sin_addr.s_addr = inet_addr(IP);
value.msg.type = 'L';
printf("输入用户名:");
scanf("%s",value.msg.name);
while(getchar()!='\n');
if(sendto(value.cfd,&value.msg,sizeof(value.msg),0,(struct sockaddr *)&(value.sin),sizeof(value.sin)) < 0){
ERR_MSG("sendto");
return -1;
}
printf("登录成功\n");
pthread_t tid;
pthread_create(&tid,NULL,deal_cli_msg,&value);
pthread_detach(tid);
struct MSG jmsg;
ssize_t res = 0;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while(1){
memset(jmsg.text,0,sizeof(jmsg.text));
res = recvfrom(value.cfd,&jmsg,sizeof(jmsg),0,(struct sockaddr*)&cin,&addrlen);
if(res < 0){
ERR_MSG("recvfrom");
return -1;
}
if('L' == jmsg.type){
printf("%s上线\n",jmsg.name);
}else if('S' == jmsg.type){
printf("服务器:%s\n",jmsg.text);
}else if('C' == jmsg.type){
printf("%s:%s\n",jmsg.name,jmsg.text);
}else if('Q' == jmsg.type){
if(strcmp(jmsg.name,value.msg.name) == 0){
break;
}else{
printf("%s已下线\n",jmsg.name);
}
}
}
close(value.cfd);
return 0;
}
void *deal_cli_msg(void *arg)
{
struct sockaddr_in sin = (*(struct Node*)arg).sin;
int cfd = (*(struct Node*)arg).cfd;
struct MSG msg = (*(struct Node*)arg).msg;
while(1){
memset(msg.text,0,sizeof(msg.text));
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text)-1] = '\0';
msg.type = 'C';
if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr *)&(sin),sizeof(sin)) < 0){
ERR_MSG("sendto");
break;
}else{
if(strcmp(msg.text,"quit") == 0){
msg.type = 'Q';
if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr *)&(sin),sizeof(sin)) < 0){
ERR_MSG("sendto");
break;
}
break;
}
}
}
close(cfd);
pthread_exit(NULL);
}