• 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> ",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 ");

    //填充结构体
    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] = '';
    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] = '';
    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. ");
    }
    else{
    sendmsg.type = 'Q';
    sendto(socket_fd,&sendmsg,sizeof(sendmsg),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    printf("offline. ");
    close(socket_fd);
    kill(getppid(), SIGKILL);
    return -1;
    }
    }
    }else{
    while(1){
    recvfrom(socket_fd, &recvmsg, sizeof(recvmsg),0,NULL,NULL);
    printf(" %s said:%s ",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> ",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 ");
    //填充结构体
    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 ");

    //定义发送接收缓存
    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] = '';
    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 : ");
    printf("%s said:%s ",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 ",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 ",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;
    }

    }

    }

  • 相关阅读:
    Asp.Net服务器Cassini
    Vista系统Administrator帐户的激活与禁用
    SqlServer中的Top * With Ties
    SqlServer建远程服务连接
    SqlServer2005安装成功后补加Sa用户
    列出某个表中所有的列名
    水晶报表周期性打开报表失败
    Asp.net中文cookie的乱码问题
    HTML数据库编程、JavaScript数据库编程
    试图索引的限制
  • 原文地址:https://www.cnblogs.com/huiji12321/p/11378841.html
Copyright © 2020-2023  润新知