第一次写udp通信,没想到能这么快完成;
现在看来显得有些限制和臃肿,没有进行优化,不过确实能实现局域网内的聊天室功能;
一、服务器模块
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
typedef struct msg_t
{
char name[128];
char text[128];
}MSG_t;
typedef struct node
{
union
{
int len;
char user_name[23];
};
struct sockaddr_in addr;
struct node* next;
}node;
node*head_creat();
node*creat_node(char*name,sa_family_t family,in_port_t port,in_addr_t addr);
void insert_head(char*name,node*H,sa_family_t family,in_port_t port,in_addr_t addr);
void dele_data(node*H,struct sockaddr_in *caddr,size_t len);
char *search_data(node*H,struct sockaddr_in *caddr,size_t len);
MSG_t text;
int main(int argc, char const *argv[])
{
//1.创建数据报套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
//ipv4
struct sockaddr_in serveraddr, caddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");
socklen_t len = sizeof(caddr);
//绑定
if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("bind err.");
return -1;
}
node*H=head_creat();
//循环收消息
char buf[128]="";
char user_name[23];
int recvbyte;
while (1)
{
recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
if (recvbyte < 0)
{
perror("recvfrom err.");
return -1;
}
printf("ip:%s port:%d buf:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);
if(!strncmp(buf,"User name",9))
{
memset(user_name,0,23);
strncpy(user_name,buf+9,23);
insert_head(user_name,H,caddr.sin_family,caddr.sin_port,caddr.sin_addr.s_addr);
memset(buf,0,128);
strncpy(buf,"Login successful",17);
sendto(sockfd, buf,sizeof(buf), 0, (struct sockaddr *)&caddr, sizeof(caddr));
if(H->len>1)
{
node*p=H->next->next;
memset(buf,0,128);
strcpy(buf,user_name);
strcat(buf," is logged in");
for(int i=0;i<H->len-1;i++)
{
sendto(sockfd,buf,sizeof(buf), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
p=p->next;
}
}
}
else if(!strncmp(buf,"quit",5))
{
memset(buf,0,128);
char quit_name[23];
char*q_name=search_data(H,&caddr,len);
strcpy(quit_name,q_name);
dele_data(H,&caddr,len);
if(H->len>0)
{
node*p=H->next;
memset(buf,0,128);
strcpy(buf,user_name);
strcat(buf," logs out");
for(int i=0;i<H->len;i++)
{
sendto(sockfd,buf,sizeof(buf), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
p=p->next;
}
}
}
else
{
char test_name[23];
char*t_name=search_data(H,&caddr,len);
strcpy(test_name,t_name);
strcpy(text.name,test_name);
strncat(text.name," Send a message:",17);
strcpy(text.text,buf);
node*p=H->next;
for(int i=0;i<H->len;i++)
{
sendto(sockfd,text.name,sizeof(text.name), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
sendto(sockfd,text.text,sizeof(text.text), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
p=p->next;
}
}
}
close(sockfd);
return 0;
}
node*head_creat()
{
node*H=(node*)malloc(sizeof(node));
if(NULL==H)
{
printf("内存申请失败\n");
return NULL;
}
else
{
H->len=0;
H->next=NULL;
printf("内存申请成功\n");
return H;
}
}
node*creat_node(char*name,sa_family_t family,in_port_t port,in_addr_t addr)
{
node*p=(node*)malloc(sizeof(node));
if(NULL==p)
{
printf("内存申请失败\n");
return NULL;
}
else
{
strcpy(p->user_name,name);
p->addr.sin_family=family;
p->addr.sin_port=port;
p->addr.sin_addr.s_addr=addr;
p->next=NULL;
return p;
}
}
void insert_head(char*name,node*H,sa_family_t family,in_port_t port,in_addr_t addr)
{
if(H==NULL)
{
printf("入参为空,请检查\n");
return;
}
node*p=creat_node(name,family,port,addr);
p->next=H->next;
H->next=p;
H->len++;
}
void dele_data(node*H,struct sockaddr_in *caddr,size_t len)
{
if(H==NULL)
{
printf("入参为空\n");
return;
}
struct sockaddr_in *d_addr;
node*p=H;
for(int i=0;i<H->len;i++)
{
d_addr=&p->next->addr;
if(!memcmp(caddr,d_addr,len))
{
node*q=p->next;
p->next=p->next->next;
free(q);
H->len--;
return;
}
else
{
p=p->next;
}
}
printf("err not dele\n");
}
char *search_data(node*H,struct sockaddr_in *caddr,size_t len)
{
if(H==NULL)
{
printf("入参为空\n");
return NULL;
}
struct sockaddr_in *s_addr;
node*p=H;
for(int i=0;i<H->len;i++)
{
s_addr=&p->next->addr;
if(!memcmp(caddr,s_addr,len))
{
return p->next->user_name;
}
else
{
p=p->next;
}
}
printf("err not serch\n");
}
二、客户端模块
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
//1.创建数据报套接子
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
//ipv4
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len = sizeof(serveraddr);
char buf[128] = "User name";
char name[119];
int recvbyte;
//输入用户名
printf("please input User name\n");
fgets(name, sizeof(name), stdin);
if (name[strlen(name) - 1] == '\n')
name[strlen(name) - 1] = '\0';
strcat(buf, name);
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
pid_t pid = fork();
if (pid < 0)
{
perror("fork err\n");
return -1;
}
else if (pid == 0)
{
while (1)
{
recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, &len);
if (recvbyte < 0)
{
perror("recv server err\n");
return -1;
}
printf("%s\n", buf);
}
}
else
{
while (1)
{
fgets(buf, sizeof(buf), stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if(!strncmp(buf,"quit",5))
{
kill(pid,SIGINT);
wait(NULL);
break;
}
}
}
close(sockfd);
return 0;
}