zoukankan      html  css  js  c++  java
  • step5 . day6 网络编程 基于TCP协议的多并发模式(使用多进程、多线程、select函数分别实现)

    实现TCP服务器端多路并发的方法有①多进程②多线程③IO多路复用(select poll epoll函数)

    1.多进程实现并发模式(仅在服务器端更改之前代码实现)

    服务器端
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <linux/in.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>

    #define SIZE 128

    void handler(int sign);
    int main(int argc, const char *argv[])
    {
    if(argc<2){
    printf("Usrmsg:%s <Port> ",argv[0]);
    return -1;
    }
    //1.创建套接字文件,用于链接
    int socket_fd;
    socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd == -1){
    perror("socket");
    return -1;
    }
    printf("socket Created ok ");

    //填充结构体sockaddr_in,用于传参
    int bind_fd;
    struct sockaddr_in serveraddr,connectaddr; //定义填充的结构体
    bzero((void *)&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET; //IPV4协议
    serveraddr.sin_port = htons(atoi(argv[1])); //本地端口号转化位网络字节码
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);//本地IP转化位网络字节码,任意IP
    //2.绑定socket文件描述符、端口、IP
    bind_fd = bind(socket_fd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    if(bind_fd == -1){
    perror("bind");
    return -1;
    }
    printf("bind ok ");

    //3.监听,将套接字文件属性该主动为被动模式
    int listen_fd;
    listen_fd = listen(socket_fd,10);

    if(listen_fd == -1){
    perror("listen");
    return -1;
    }
    printf("listen ok ");


    int addrsize = sizeof(connectaddr);
    int accept_fd;
    int recvbyte;

    char bufrecv[SIZE] = {0};
    while(1){

    accept_fd = accept(socket_fd,(struct sockaddr*)&connectaddr,&addrsize);
    if(accept_fd == -1){
    perror("accept");
    return -1;
    }

    printf("connect ok ");
    pid_t pid = fork();

    if(pid < 0){
    perror("fork");
    return -1;
    }

    if(pid == 0){
    close(socket_fd);
    while(1){
    memset(bufrecv,0,SIZE);
    int port = ntohs(connectaddr.sin_port);
    char *ip = (char *)(inet_ntoa(connectaddr.sin_addr.s_addr));

    recvbyte = recv(accept_fd, bufrecv,sizeof(bufrecv),0);

    if(recvbyte <= 0){
    printf("client failed connect ");
    return -1;
    }
    printf("IP:%s Port:%d online. send: %s ",ip,port,bufrecv);
    }
    // close(accept_fd);
    }
    else{
    close(accept_fd);
    signal(SIGCHLD,handler);

    }
    }

    close(socket_fd);

    return 0;
    }
    void handler(int sign){

    waitpid(-1,NULL,WNOHANG);
    printf("signal = %d ",sign);
    }

    2.多线程实现并发


    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <linux/in.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <pthread.h>

    #define SIZE 128

    void *connectfun(void *arg);
    int main(int argc, const char *argv[])
    {
    if(argc<2){
    printf("Usrmsg:%s <Port> ",argv[0]);
    return -1;
    }
    //1.创建套接字文件,用于链接
    int socket_fd;
    socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd == -1){
    perror("socket");
    return -1;
    }
    printf("socket Created ok ");

    //填充结构体sockaddr_in,用于传参
    int bind_fd;
    struct sockaddr_in serveraddr,connectaddr; //定义填充的结构体
    bzero((void *)&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET; //IPV4协议
    serveraddr.sin_port = htons(atoi(argv[1])); //本地端口号转化位网络字节码
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);//本地IP转化位网络字节码,任意IP
    //2.绑定socket文件描述符、端口、IP
    bind_fd = bind(socket_fd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    if(bind_fd == -1){
    perror("bind");
    return -1;
    }
    printf("bind ok ");

    //3.监听,将套接字文件属性该主动为被动模式
    int listen_fd;
    listen_fd = listen(socket_fd,10);

    if(listen_fd == -1){
    perror("listen");
    return -1;
    }
    printf("listen ok ");


    int addrsize = sizeof(connectaddr);
    int accept_fd;

    while(1){

    accept_fd = accept(socket_fd,(struct sockaddr*)&connectaddr,&addrsize);
    if(accept_fd == -1){
    perror("accept");
    return -1;
    }
    printf("connect ok ");

    pthread_t pid ;
    pthread_create(&pid, NULL,connectfun,(void*)&accept_fd);

    }

    close(socket_fd);
    return 0;

    }
    void *connectfun(void *arg){
    pthread_detach(pthread_self());
    char bufrecv[SIZE] = {0};
    int recvbyte;
    while(1){

    memset(bufrecv,0,SIZE);

    recvbyte = recv(*(int *)arg, bufrecv,sizeof(bufrecv),0);

    if(recvbyte <= 0){
    printf("client failed connect ");
    return NULL;
    }
    printf("send: %s ",bufrecv);
    }
    }

    3.select函数实现多并发


    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <linux/in.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    #define SIZE 128

    int main(int argc, const char *argv[])
    {
    if(argc<2){
    printf("Usrmsg:%s <Port> ",argv[0]);
    return -1;
    }
    //1.创建套接字文件,用于链接
    int socket_fd;
    socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd == -1){
    perror("socket");
    return -1;
    }
    printf("socket Created ok ");

    //填充结构体sockaddr_in,用于传参
    int bind_fd;
    struct sockaddr_in serveraddr,connectaddr; //定义填充的结构体
    bzero((void *)&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET; //IPV4协议
    serveraddr.sin_port = htons(atoi(argv[1])); //本地端口号转化位网络字节码
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);//本地IP转化位网络字节码,任意IP
    //2.绑定socket文件描述符、端口、IP
    bind_fd = bind(socket_fd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    if(bind_fd == -1){
    perror("bind");
    return -1;
    }
    printf("bind ok ");

    //3.监听,将套接字文件属性该主动为被动模式
    int listen_fd;
    listen_fd = listen(socket_fd,10);

    if(listen_fd == -1){
    perror("listen");
    return -1;
    }
    printf("listen ok ");

    //创建监听集合
    fd_set readfds,tempfds;
    //清空集合
    FD_ZERO(&readfds);
    FD_ZERO(&tempfds);
    //将关心的文件描述符加入集合
    FD_SET(0,&readfds);
    FD_SET(socket_fd,&readfds);

    //设置最大监听个数
    int maxfd = socket_fd;

    int addrsize = sizeof(connectaddr);
    int accept_fd;
    int recvbyte;
    int val;
    char bufsend[SIZE] = {0};
    char bufrecv[SIZE] = {0};
    while(1){

    tempfds = readfds;
    val = select(maxfd + 1,&tempfds,NULL,NULL,NULL);
    //4.阻塞函数,等待客户链接请求,不关心链接的是那个客户端,填NULL
    if(val < 0)
    {
    perror("select failed.");
    return -1;
    }
    int i = 0;
    for(i = 0;i<maxfd+1;i++){
    if(FD_ISSET(i,&tempfds)){

    if(i == 0)
    {
    fgets(bufsend,sizeof(bufsend),stdin);

    send(socket_fd, bufsend, sizeof(bufsend),0);
    printf("send ok. ");
    }
    if(i == socket_fd)
    {
    accept_fd = accept(socket_fd,(struct sockaddr*)&connectaddr,&addrsize);
    if(accept_fd == -1){
    perror("accept");
    return -1;
    }

    printf("accept ok ");
    int port = ntohs(connectaddr.sin_port);
    char *ip = (char *)(inet_ntoa(connectaddr.sin_addr.s_addr));
    printf("IP:%s Port:%d online. ",ip,port);
    FD_SET(accept_fd,&readfds);
    maxfd = maxfd > accept_fd ? maxfd : accept_fd;

    }
    else{
    recvbyte = recv(i, bufrecv,sizeof(bufrecv),0);
    if(recvbyte <= 0)
    {
    FD_CLR(i,&readfds);
    close(i);
    continue;
    }

    printf("%s ",bufrecv);

    }
    }
    }
    }

    close(socket_fd);
    close(accept_fd);
    return 0;
    }

  • 相关阅读:
    [转].net自定义验证控件CustomValidator的使用
    After Effects CS4入门经典—高手之路
    [转]用JS获取地址栏参数的方法(超级简单)
    SpringBoot中通过SpringBootServletInitializer如何实现容器初始化
    SpringBoot之二:部署Spring Boot应用程序方式
    Zookeeper学习(八):Zookeeper的数据发布与订阅模式
    Dubbo各种协议详解
    Annotation之四:注解中的-Xlint:unchecked和 -Xlint:deprecation
    mina在spring中的配置多个端口
    Mina2中IoService
  • 原文地址:https://www.cnblogs.com/huiji12321/p/11380865.html
Copyright © 2011-2022 走看看