step5 . day5 网络编程 基于UDP协议的多人网络在线聊天功能
模拟在线群聊功能,使用多进程完成聊天内容的接受和服务器端的转发,demo代码记录参考
//client_chat_UDP code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/in.h>
#include <sys/select.h>
#include <signal.h>
#define N 128
typedef struct massage{
char type;
char name[32];
char buf[N];
}MSG;
int main(int argc, const char *argv[])
{
//判断输入、提示格式
if(argc<3){
printf("Usrmag:%s <server IP> <PORT>\n",argv[0]);
return -1;
}
//创建通信套接字 使用UDP通讯协议
int socket_fd;
socket_fd = socket(AF_INET,SOCK_DGRAM,0);
if(socket_fd < 0){
perror("socket failed:");
return -1;
}
printf("socket ok\n");
//填充结构体
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//定义发送接收缓存
MSG sendmsg,recvmsg;
printf("please input your name :");
fgets(sendmsg.name,32,stdin);
sendmsg.name[strlen(sendmsg.name)-1] = '\0';
sendmsg.type = 'L';
sprintf(sendmsg.buf,"%s login",sendmsg.name);
sendto(socket_fd, &sendmsg, sizeof(sendmsg),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
//创建多进程,一个用来接收,一个用来发送
int pid;
pid = fork();
if(pid < 0){
perror("fork failed:");
return -1;
}else if(pid == 0){
while(1){
printf("send msg>> ");
fgets(sendmsg.buf,N,stdin);
sendmsg.buf[strlen(sendmsg.buf)-1] = '\0';
if(strncmp(sendmsg.buf,"quit",4)!=0){
sendmsg.type = 'B';
sendto(socket_fd,&sendmsg,sizeof(sendmsg),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
printf("send ok.\n");
}
else{
sendmsg.type = 'Q';
sendto(socket_fd,&sendmsg,sizeof(sendmsg),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
printf("offline.\n");
close(socket_fd);
kill(getppid(), SIGKILL);
return -1;
}
}
}else{
while(1){
recvfrom(socket_fd, &recvmsg, sizeof(recvmsg),0,NULL,NULL);
printf("\n%s said:%s\n",recvmsg.name,recvmsg.buf);
}
}
close(socket_fd);
return 0;
}
//server_chat_UDP code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/in.h>
#include <sys/select.h>
#include <stdlib.h>
#define N 128
//消息结构体
typedef struct massage{
char type;
char name[32];
char buf[N];
}MSG;
//登陆用户链表
typedef struct node{
struct node *next;
char name[32];
struct sockaddr_in addr;
}linklist;
//模块操作判断函数
void login(int sockfd,MSG msg,struct sockaddr_in clientaddr,struct sockaddr_in serveraddr,linklist *head);
void quit(int sockfd,MSG msg,struct sockaddr_in serveraddr,linklist *head);
void broadcast(int socket_fd,MSG msg,linklist *head);
//链表创建函数
linklist * linklist_create(){
linklist *h = (linklist *)malloc(sizeof(linklist));
h->next = NULL;
return h;
}
int main(int argc, const char *argv[])
{
//判断输入、提示格式
if(argc<2){
printf("Usrmag:%s <PORT>\n",argv[0]);
return -1;
}
//创建通信套接字 使用UDP通讯协议
int socket_fd;
socket_fd = socket(AF_INET,SOCK_DGRAM,0);
if(socket_fd < 0){
perror("socket failed:");
return -1;
}
printf("socket ok\n");
//填充结构体
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(atoi(argv[1]));
socklen_t addrlen = sizeof(struct sockaddr_in);
socklen_t clientaddrlen = sizeof(struct sockaddr_in);
int bind_fd;
bind_fd = bind(socket_fd,(struct sockaddr*)&serveraddr,addrlen);
if(bind_fd < 0){
perror("bind failed:");
return -1;
}
printf("bind ok\n");
//定义发送接收缓存
MSG sendmsg,recvmsg;
//创建用户链表表头
linklist *head = linklist_create();
//创建多进程,一个用来接收,一个用来广播
int pid;
pid = fork();
if(pid < 0){
perror("fork failed:");
return -1;
}else if(pid ==0){ //子进程用来客户端的发送广播
while(1){
strcpy(sendmsg.name,"server");
sendmsg.type = 'B';
fgets(sendmsg.buf,N,stdin);
sendmsg.buf[strlen(sendmsg.buf)-1] = '\0';
sendto(socket_fd,&sendmsg,sizeof(sendmsg),0,(struct sockaddr *)&serveraddr,addrlen);
}
}else{
//父进程接受客户端发送消息
while(1){
recvfrom(socket_fd,&recvmsg,sizeof(recvmsg),0,(struct sockaddr *)&clientaddr,&clientaddrlen);
switch(recvmsg.type){
case 'L':
login(socket_fd,recvmsg,clientaddr,serveraddr,head);
break;
case 'B':
//服务器转发
broadcast(socket_fd,recvmsg,head);
break;
case 'Q':
//退出
printf("quit wait :\n");
printf("%s said:%s\n",recvmsg.name,recvmsg.buf);
quit(socket_fd,recvmsg,serveraddr,head);
break;
}
}
}
close(socket_fd);
return 0;
}
void login(int sockfd,MSG msg,struct sockaddr_in clientaddr,struct sockaddr_in serveraddr,linklist *head){
printf("%s login\n",msg.name);
linklist *p = head;
while(p->next != NULL){
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->next->addr),sizeof(serveraddr));
p = p->next;
}
linklist *temp = linklist_create();
strcpy(temp->name,msg.name);
temp->addr = clientaddr;
temp->next = NULL;
p->next = temp;
}
void quit(int sockfd,MSG msg,struct sockaddr_in serveraddr,linklist *head){
linklist *p = head;
while(strcmp(p->next->name,msg.name)!=0){
p = p->next;
}
linklist *temp = p->next;
p->next = temp->next;
sprintf(msg.buf,"%s offline",msg.name);
msg.type = 'B';
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
free(temp);
temp = NULL;
}
void broadcast(int sockfd,MSG msg,linklist *head){
printf("%s said:%s\n",msg.name,msg.buf);
linklist *temp = head->next;
while(temp != NULL){
if(strcmp(temp->name,msg.name) ==0){
temp = temp->next;
}
else{
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(temp->addr),sizeof(temp->addr));
temp = temp->next;
}
}
}