基于UDP的聊天系统 Ubuntu14.04

版权声明:转载请注明出处 https://blog.csdn.net/qq_37689106/article/details/84189959

总体思想:
先是创建一个链表用来存放连入服务器的sockaddr_in信息,有人登录加入链表节点,有人下线删除节点。
创建一个类似消息队列结构的结构体,用来存放用户的当前状态的类型、名字、消息。
将每个UDP客户端连接服务器后将其的sockaddr_in信息加入到链表中,通过数据的类型去判断服务器去执行哪个函数(登录广播、转发聊天信息、下线广播)。
1、UDP服务器部分
第一点 运行服务器会fork()一个子进程,该子进程用于服务器本身发送聊天的内容,父进程用于接收客户端的消息。
第二点 服务器通过接收的信息去判断类型(‘L’ ‘C’ ‘Q’)执行相应的处理函数。
第三点 处理函数 type = ‘L’ 会向当前链表中除自己以外的所有成员广播 name上线,随后将其加入到链表中。type = ‘C’ 会向当前链表中除自己以外的所有成员广播消息内容。type = ‘Q’ 首先是通知所有用户name下线,在链表中将其删除。
2、客户端部分
第一点 运行客户端程序,首先是将消息类型设置成’L’,令服务器广播告知其他成员该用户上线。
第二点 随后创建一个子进程,该进程用于发送聊天的消息,父进程用于接收服务器转发的其他用户发过来的消息。
第三点 当子进程判断输入的消息是"quit"将数据类型改成’Q’,以便服务器将其在链表中删除,并告知其他用户某人下线。
service:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

#define  N  128 

typedef struct msg
{
    char type;
    char name[N];
    char text[N];
}msg_t;

int main(int argc, const char *argv[])
{
    char buf[N] = {0};
    int sockfd,ret,newsockfd;
    struct sockaddr_in server,client;
    pid_t pid;
    msg_t msg;
    memset(&msg,0,sizeof(msg)) ;
    if(argc != 3)
    {
        printf("运行程序时带入ip 和 port\n");
        exit(-1);
    }
    socklen_t addrlen = sizeof(client);
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        perror("socket");
        exit(-1);
    }
    printf("sockfd=%d\n",sockfd);
    memset(&server,0,sizeof(server));
    server.sin_family = AF_INET ;
    server.sin_port   = htons( atoi(argv[2]) );
    server.sin_addr.s_addr   = inet_addr(argv[1]); 

    msg.type = 'L';
    printf("input your name >:");
    fgets(msg.name,N,stdin);
    msg.name[strlen(msg.name) -1 ] = 0 ; 
    ret  = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&server,addrlen) ;
    if(ret < 0)
    {
        perror("write");
        exit(-1);
    }

    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if(pid == 0)
    {
        msg.type = 'C';
        while(1)
        {
            printf(">:");
            fgets(msg.text,N,stdin);
            if(strncmp(msg.text,"quit",4) == 0 )
            {
                msg.type = 'Q';
                ret  = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&server,addrlen) ;
                if(ret < 0)
                {
                    perror("write");
                    exit(-1);
                }
                kill(getppid(),SIGUSR1);
                exit(0);
            }
            ret  = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&server,addrlen) ;
            if(ret < 0)
            {
                perror("write");
                exit(-1);
            }
        }
        
    }
    else 
    {
        while(1)
        {
            ret = recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
            if(ret  < 0)
            {
                printf("read");
                exit(-1);
            }
            printf("%s\n",msg.text);

        }

    }
    close(sockfd);


    
    return 0;
}

client:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define  N  128

typedef struct node 
{
    struct sockaddr_in  addr; //ip 地址
    struct node * next;
}linklist_t;   //链表

typedef struct msg
{
    char type;
    char name[N];
    char text[N];
}msg_t;

linklist_t * create_empty_linkist(void)
{
    linklist_t * h = (linklist_t *)malloc(sizeof(linklist_t)) ;
    h->next = NULL;
    memset(&h->addr,0,sizeof(h->addr));
    return h;
}

int process_login(linklist_t * h,int sockfd,struct sockaddr_in *addr,msg_t *msgp)
{
    linklist_t * p = h->next; 
    int ret ;
    sprintf(msgp->text,"%s login",msgp->name);
    while(p != NULL)
    {
        if(memcmp(&p->addr,addr,sizeof(*addr)) != 0 )
        {
            ret = sendto(sockfd,msgp,sizeof(msg_t),0,(struct sockaddr *)&p->addr,sizeof(p->addr));
            if(ret  < 0)
            {
                printf("sendto");
                exit(-1);
            }
        }
        p = p->next;
    }
    p = (linklist_t * )malloc(sizeof(linklist_t)) ; //倒叙插入法
    p->next = h->next;
    h->next = p ; 
    p->addr = *addr;

    return 0;
    
}
int process_chat(linklist_t * h,int sockfd,struct sockaddr_in *addr,msg_t *msgp)
{
    linklist_t * p = h->next; 
    char buf[128] = {0};
    int ret ;
    sprintf(buf,"%s said %s",msgp->name,msgp->text);
    strcpy(msgp->text,buf);
    while(p != NULL)
    {
        if(memcmp(&p->addr,addr,sizeof(*addr)) != 0 )
        {
            ret = sendto(sockfd,msgp,sizeof(msg_t),0,(struct sockaddr *)&p->addr,sizeof(p->addr));
            if(ret  < 0)
            {
                printf("sendto");
                exit(-1);
            }
        }
        p = p->next;
    }
    return 0;
    
}
int process_quit(linklist_t * h,int sockfd,struct sockaddr_in *addr,msg_t *msgp)
{
    linklist_t * p = h->next; 
    linklist_t * q;
    char buf[128] = {0};
    int ret ;
    sprintf(msgp->text,"%s offline",msgp->name);
    while(p != NULL)
    {
        if(memcmp(&p->addr,addr,sizeof(*addr)) != 0 )
        {
            ret = sendto(sockfd,msgp,sizeof(msg_t),0,(struct sockaddr *)&p->addr,sizeof(p->addr));
            if(ret  < 0)
            {
                printf("sendto");
                exit(-1);
            }
        }
        p = p->next;
    }
    p = h ; 
    while(p->next != NULL)
    {
        if(memcmp(&p->next->addr,addr,sizeof(*addr)) == 0 )
        {
            q = p->next;
            p->next = p->next->next;
            free(q);
            break ;
        }
        p = p->next;
    }
    return 0;
    
}

int main(int argc, const char *argv[])
{
    char buf[N] ={0};
    int sockfd,ret,newsockfd;
    struct sockaddr_in myaddr,client;
    pid_t pid;
    msg_t msg;
    memset(&msg,0,sizeof(msg));
    if(argc != 3)
    {
        printf("运行程序时带入ip 和 port\n");
        exit(-1);
    }
    socklen_t addrlen = sizeof(client);
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        perror("socket");
        exit(-1);
    }
    printf("sockfd=%d\n",sockfd);
    memset(&myaddr,0,sizeof(myaddr));
    myaddr.sin_family = AF_INET ;
    myaddr.sin_port   = htons(atoi(argv[2]));
    myaddr.sin_addr.s_addr   = inet_addr(argv[1]); 
    ret = bind(sockfd,(struct sockaddr *)&myaddr,sizeof(myaddr)) ; // 给socket 一个固定的ip 和端口 
    if(ret < 0)
    {
        perror("bind");
        exit(-1);
    }
    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if(pid == 0 ) // 发送广播
    {
        msg.type = 'C';
        while(1)
        {
            printf(">:");
            fgets(msg.text,N,stdin);
            strcpy(msg.name,"server");
            ret  = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&myaddr,addrlen) ;
            if(ret < 0)
            {
                perror("write");
                exit(-1);
            }
            memset(buf,0,N);
        }
        
    }
    else // parent 
    {
        linklist_t * H = create_empty_linkist();
        while(1)
        {
            ret = recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&client,&addrlen);
            if(ret  < 0)
            {
                printf("read");
                exit(-1);
            }
            printf("msg.type = %c\n",msg.type);
            printf("msg.name = %s\n",msg.name);
            printf("msg.text = %s\n",msg.text);
            switch(msg.type)
            {
                case 'L':
                    process_login(H,sockfd,&client,&msg);
                    break ; 
                case 'C': 
                    process_chat(H,sockfd,&client,&msg);
                    break ;
                case 'Q':
                    process_quit(H,sockfd,&client,&msg);
                    break ; 
                default:
                    break ;
            }
#if 0
            ret = sendto(sockfd,buf,N,0,(struct sockaddr *)&client,addrlen);
            if(ret  < 0)
            {
                printf("sendto");
                exit(-1);
            }
#endif

        }


    }

    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37689106/article/details/84189959