当前位置: 首页 > news >正文

网络编程之客户端通过服务器与另外一个客户端交流

服务器使用select模型搭建,客户端1使用线程搭建,客户端2使用poll模型搭建,

使用时需要先运行服务器,具体编译可看我最后的图片

 head.h头文件

#ifndef __HEAD_H_
#define __HEAD_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pwd.h>
#include <dirent.h>
#include <wait.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 #include <poll.h>
#include <signal.h>
#define PRINTF_ERROR(a) {perror(a);return -1;}
#endif

 服务器搭建代码

server_select.c

#include <head.h>
enum Type{
    TYPE_LOGIN,
    TYPE_REDIST
};
typedef struct Pack{ //协议包
    int packsize;
    enum Type type;
    char buf[4096];
    int used;

}pack_t;   
void freeList(char** list){
    for(int i=0;list[i]!=NULL;i++){
        free(list[i]);
    }
    free(list);
}

char** analysis(pack_t pack){     //解析客户端发来的协议包
    char* buf=pack.buf;
    int readed_size=0;
    char** list = calloc(1,80);
    int i=0;//
    while(1){
        short size = *(short*)(buf+readed_size);
        if(size==0)
            break;
        readed_size+=2;
        char temp[size+1];
        memset(temp,0,size+1);
        memcpy(temp,buf+readed_size,size);
        readed_size+=size;

        list[i]=calloc(1,size+1);
        strcpy(list[i],temp);
        i++;
    }
    return list;

}
void insert_client(int* arr,int client,int* len){ //将客户端的描述符放入数组
    arr[*len]=client;
    (*len)++;
}
void remove_client(int* arr,int client,int* len){
    int i=0,j=0;
    for(i=0;i<*len;i++){
        if(arr[i]==client)
            break;
    }
    if(i==*len)
        return;
    for(j=i;j<*len;j++){
        arr[j]=arr[j+1];
    }
    arr[j]=0;
    (*len--);
}
int main(int argc, const char *argv[])
{
    if(argc<2){
        printf("请输入端口号:\n");
        return 1;
    }
    int port = atoi(argv[1]);
    int server = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr = {0};

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    if(bind(server,(struct sockaddr*)&addr,sizeof(addr))==-1){
        perror("bind");
        return -1;
    }
    listen(server,50);

    int  client_arr[64]={0};//存放所有客户端套接字的数组
    int arr_len=0;//记录数组的长度
    fd_set readfds;//创建一个select的监听列表
    FD_ZERO(&readfds);//初始化监听列表
    FD_SET(server,&readfds);//将服务器套接字放入监听列表中
    FD_SET(STDIN_FILENO,&readfds);//将标准输入流放入监听列表中

    while(1){
        fd_set temp=readfds;
        select(1024,&temp,0,0,0);
        if(FD_ISSET(0,&temp)){  输入流激活
            char buf[1024]="";
            scanf("%s",buf);
            getchar();
            printf("键盘输入数据:%s\n",buf);
        }
        if(FD_ISSET(server,&temp)){  服务器激活
            int client=accept(server,0,0);
            printf("有客户端链接\n");
            FD_SET(client,&readfds);
            insert_client(client_arr,client,&arr_len);
        }
        for(int i=0;i<arr_len;i++){
            int client = client_arr[i];
            if(FD_ISSET(client,&temp)){ //客户端激活

                pack_t pack={0};
                int size=0;
                int res=read(client,&size,4);
                if(res ==0){
                    printf("客户端断开链接\n");
                    FD_CLR(client,&readfds);
                    remove_client(client_arr,client,&arr_len);
                    close(client);
                    break;
                }
                pack.packsize=size;
                read(client,(char*)&pack+4,size-4);
                char** list=analysis(pack);
                for(int j=0;j<arr_len;j++){    
                    if(client_arr[i]!=client_arr[j]){
                        if(write(client_arr[j],&pack,size)<=0)
                            PRINTF_ERROR("write error");
                    }
                }
                printf("%s\n",list[0]);
                freeList(list);

            }
        }
    }
    return 0;
}

 客户端1

client1.c

#include <head.h>
#include <pthread.h>
enum Type{
    TYPE_REGIST,
    TYPE_LOGIN
};

typedef struct Pack{
    int packsize;
    enum Type type;
    char buf[4096];
    int used;
}pack_t;

void append(pack_t* pack,const char* str){
    char* buf=pack->buf;
    short size=strlen(str);
    *(short*)(buf+pack->used)=size;
    pack->used+=2;
    memcpy(buf+pack->used,str,size);
    pack->used+=size;
    pack->packsize=pack->used+8;
}
void freeList(char** list){
    for(int i=0;list[i]!=NULL;i++){
        free(list[i]);
    }                                                  
    free(list);
}

char** analysis(pack_t pack){
    char* buf=pack.buf;
    int readed_size=0;
    char** list = calloc(1,80);
    int i=0;//
    while(1){
        short size = *(short*)(buf+readed_size);
        if(size==0)
            break;
        readed_size+=2;
        char temp[size+1];
        memset(temp,0,size+1);
        memcpy(temp,buf+readed_size,size);
        readed_size+=size;

        list[i]=calloc(1,size+1);
        strcpy(list[i],temp);
        i++;
    }
    return list;

}


void* Write(void* arg){
    int client =*(int *)arg;
    while(1){
        char str[20]="";
        pack_t pack={0};
        pack.type=TYPE_REGIST;
        scanf("%19s",str);
        getchar();
        append(&pack,str);
        write(client,&pack,pack.packsize);
    }
    pthread_exit(NULL);

}
void* Read(void* arg){
    int client =*(int *)arg;
    while(1){
        pack_t pack1={0};
        int size=0;
        read(client,&size,4);
        read(client,(char*)&pack1+4,size-4);
        char** list=analysis(pack1);
        printf("客户端1:%s\n",list[0]);
    
        freeList(list);


    }
    pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
    if(argc<2){
        printf("请输入端口号\n");
        return -1;
    }
    int port=atoi(argv[1]);
    int client=socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in addr={0};
    addr.sin_family=AF_INET;
    addr.sin_port=htons(port);
    addr.sin_addr.s_addr=inet_addr("0.0.0.0");
    if(connect(client,(struct sockaddr*)&addr,sizeof(addr))==-1){
        PRINTF_ERROR("bind error");
    }

    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,Write,&client);
    pthread_create(&tid2,NULL,Read,&client);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);


    return 0;
}

客户端2

client2.c

#include <head.h>
enum Type{
    TYPE_LOGIN,
    TYPE_REDIST
};
typedef struct Pack{
    int packsize;
    enum Type type;
    char buf[4096];
    int used;

}pack_t;
void append(pack_t* pack,const char* str){
    char* buf = pack->buf;
    short size = strlen(str);
    *(short*)(buf+pack->used) = size;
    pack->used +=2;
    memcpy(buf+pack->used,str,size);
    pack->used+=size;
    pack->packsize=pack->used+8;
}
// 该函数功能为:将client存入数组arr中的最后一个下标位置上,存完之后,arr数组的长度记得自增
void insert_client(struct pollfd* arr,struct pollfd client,int* len){
    arr[*len] = client;
    (*len)++;
}

// 将client从数组arr中移除,移除后记得数组长度-1
void remove_client(struct pollfd* arr,int client,int* len){
    int i = 0,j = 0;
    for(i=0;i<*len;i++){
        if(arr[i].fd == client){break;}
    }                                                                                       
    if(i == *len){return;}
    for(j=i;j<*len-1;j++){
        arr[j] = arr[j+1];
    }
    //arr[j] = 0;
    (*len)--;
}
void freeList(char** list){
    for(int i=0;list[i]!=NULL;i++){
        free(list[i]);
    }
    free(list);
}

char** analysis(pack_t pack){
    char* buf=pack.buf;
    int readed_size=0;
    char** list = calloc(1,80);
    int i=0;//
    while(1){
        short size = *(short*)(buf+readed_size);
        if(size==0)
            break;
        readed_size+=2;
        char temp[size+1];
        memset(temp,0,size+1);
        memcpy(temp,buf+readed_size,size);
        readed_size+=size;

        list[i]=calloc(1,size+1);
        strcpy(list[i],temp);
        i++;
    }
    return list;

}

int main(int argc, const char *argv[])
{
    if(argc<2){
        printf("请输入端口号:\n");
        return 1;                   
    }
    int port = atoi(argv[1]);

    int client = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    if(connect(client,(struct sockaddr*)&addr,sizeof(addr))==-1){
        perror("connect");
        return -1;
    }

    struct pollfd list[50]={0};
    int list_len=0;
    struct pollfd client_fd={fd:client,events:POLLIN,revents:0};
    struct pollfd stdin_fd={fd:0,events:POLLIN,revents:0};

    insert_client(list,client_fd,&list_len);

    insert_client(list,stdin_fd,&list_len);


    while(1){

        poll(list,list_len,-1);
        int i=0;
        for(i=0;i<list_len;i++){
            if(list[i].revents==0){
                continue;
            }
            int fd=list[i].fd;
            if(fd==0){
                char str[20]="";
                pack_t pack = {0};
                pack.type=TYPE_REDIST;
                scanf("%19s",str);
                getchar();
                append(&pack,str);
                write(client,&pack,pack.packsize);
            }else{
                pack_t pack1={0};
                int size=0;
                read(client,&size,4);
                read(client,(char*)&pack1+4,size-4);
                char** list=analysis(pack1);
                printf("客户端2:%s\n",list[0]);
                freeList(list);

            }
        }
    }

    return 0;
}

 结果

相关文章:

  • oracle删除表中重复数据
  • 正则表达式与拓展正则简单理解
  • LeetCode[93] 复原 IP 地址
  • Mimikyu综合靶场训练
  • 大数据学习(74)-Hue元数据
  • Python标准库之os模块常用方法
  • Excel Script Lab学习笔记
  • Pytorch使用手册(专题五十)—自定义运算符
  • 《Python深度学习》第三讲:神经网络
  • sqlite mmap
  • nginx配置反向代理数据库等插件的原理和方式
  • Java线程6种状态的详细说明、状态转换关系(UML展示)
  • 汽车安全确认等级-中国等保
  • springboot基于session实现登录
  • 深入解析过滤器模式(Filter Pattern):一种灵活高效的设计模式
  • 让vscode远程开发也可以图形显示
  • 基于BClinux8部署Ceph 19.2(squid)集群
  • Coco AI 智能检索 Hugo Blog 集成指南
  • 我的python学习记录
  • 【蓝桥杯】省赛:分糖果(思维/模拟)
  • 金山建设机械网站/淘宝网店怎么运营起来
  • 做图素材的网站有哪些/新媒体运营是做什么
  • 巨野做网站的/网站收录
  • 网页版微信怎么删除聊天记录/seo网站关键词排名软件
  • 网站头部 标签/网站优化排名优化
  • 淄博政府网站建设专家/病毒式营销案例