Webserver(4.5)复用

目录

端口复用

单边的close,会有一个等待的状态,这个时候有1分钟的时间,端口还开启着。这个时候再打开服务器,可能会有端口依旧绑定的情况

端口复用来重启这个端口,就能重新绑定了

cpp 复制代码
int optval=1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEPORT,&optval,sizeof(optval));
cpp 复制代码
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>


int main(){
    //1.创建socket(用于监听的套接字)
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    if(lfd==-1){
        perror("socket");
        exit(0);
    }
    int optval=1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEPORT,&optval,sizeof(optval));
    //2.绑定
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    //indet_pton(AF_INET,"192.168.227.129",saddr.sin_addr.s_addr);
    saddr.sin_addr.s_addr=INADDR_ANY;
    saddr.sin_port=htons(9999);
    int ret=bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));
    if(ret==-1){
        perror("bind");
        exit(0);
    }

    //3.监听
    ret=listen(lfd,8);
    if(ret==-1){
        perror("listen");
        exit(0);
    }

    //4.接收客户端的连接
    struct sockaddr_in clientaddr;
    socklen_t len=sizeof(clientaddr);
    int cfd=accept(lfd,(struct sockaddr *)&clientaddr,&len);
    if(cfd==-1){
        perror("accept");
        exit(0);
    }

    //输出客户端的信息
    char clientIP[16];
    inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,clientIP,sizeof(clientIP));
    unsigned short clientPort =ntohs(clientaddr.sin_port);
    printf("client ip is %s,port is %d\n",clientIP,clientPort);

    //5.通信
    char recvBuf[1024]={0};
    //获取客户端的数据
    while(1){
        
        int num=recv(cfd,recvBuf,sizeof(recvBuf),0);
        if(num==-1){
            perror("recv");
            exit(-1);
        }else if(num>0){
            printf("recv client data:%s\n",recvBuf);
        }else if(num==0){
            //表示客户端断开连接
            printf("client closed...");
            break;
        }

        //小写转大写
        for(int i=0;i<len;++i){
            recvBuf[i]=toupper(recvBuf[i]);
        }
        printf("after buf=%s\n",recvBuf);

        //大写字符串发给客户端
        ret=send(cfd,recvBuf,strlen(recvBuf)+1,0);
        if(ret==-1){
            perror("send");
            return -1;
        }

    }
    

    //关闭文件描述符
    close(cfd);
    close(lfd);

    return 0;
}
cpp 复制代码
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

int main(){

    //1.创建套接字
    int fd=socket(AF_INET,SOCK_STREAM,0);
    if(fd==-1){
        perror("socket");
        exit(-1);
    }

    //2.连接服务器端
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    inet_pton(AF_INET,"192.168.227.129",&serveraddr.sin_addr.s_addr);
    serveraddr.sin_port=htons(9999);
    int ret=connect(fd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
    if(ret==-1){
        perror("connect");
        exit(-1);
    }

    char recvBuf[1024]={0};
    //3.通信
    while(1){
        char sendBuf[1024]={0};
        fgets(sendBuf,sizeof(sendBuf),stdin);
        //给服务器发送数据
        write(fd,sendBuf,strlen(sendBuf)+1);
        
        
        int len=read(fd,sendBuf,sizeof(sendBuf));
        if(len==-1){
            perror("read");
            exit(-1);
        }else if(len>0){
            printf("recv server data:%s\n",sendBuf);
        }else if(len==0){
            //表示客户端断开连接
            printf("server closed...");
        }
    }
   

    //关闭连接
    close(fd);



    return 0;
}

I/O多路复用

select

构造一个关于文件描述符的列表

监听文件是否发送数据,告诉进程有哪些描述符需要进行I/O操作

两个客户端也可以

并没有用多进程或者多线程,只使用了select也能完成多客户端的连接

client.c

cpp 复制代码
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

int main(){

    //1.创建套接字
    int fd=socket(AF_INET,SOCK_STREAM,0);
    if(fd==-1){
        perror("socket");
        exit(-1);
    }

    //2.连接服务器端
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);
    serveraddr.sin_port=htons(9999);
    int ret=connect(fd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
    if(ret==-1){
        perror("connect");
        exit(-1);
    }


    //3.通信
    int num=0;
    while(1){
        char sendBuf[1024]={0};
        sprintf(sendBuf,"send data %d",num++);
        sleep(1);
        //给服务器发送数据
        write(fd,sendBuf,strlen(sendBuf)+1);
        
        
        int len=read(fd,sendBuf,sizeof(sendBuf));
        if(len==-1){
            perror("read");
            exit(-1);
        }else if(len>0){
            printf("recv server data:%s\n",sendBuf);
        }else if(len==0){
            //表示客户端断开连接
            printf("server closed...");
        }
    }
   

    //关闭连接
    close(fd);



    return 0;
}

select.c

cpp 复制代码
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/time.h>
#include<sys/types.h>
#include<sys/select.h>

int main(){

    //创建socket
    int lfd=socket(PF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_port=htons(9999);
    saddr.sin_family=AF_INET;
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));

    //监听
    listen(lfd,8);

    //创建一个fd_set的集合,存放的是需要检测的文件描述符
    fd_set rdset,tmp;
    FD_ZERO(&rdset);
    FD_SET(lfd,&rdset);
    int maxfd=lfd;

    while(1){
        tmp=rdset;
        //调用select系统函数,让内核帮检测哪些文件描述符有数据
        int ret=select(maxfd+1,&tmp,NULL,NULL,NULL);
        if(ret==-1){
            perror("select");
            exit(-1);
        }else if(ret==0){
            continue;
        }else if(ret>0){
            //说明检测到了有文件描述符的对应的缓冲区的数据发生了改变
            if(FD_ISSET(lfd,&tmp)){
                //表示有新的客户端连接进来了
                struct sockaddr_in cliaddr;
                int len=sizeof(cliaddr);
                int cfd=accept(lfd,(struct sockaddr *)&cliaddr,&len);

                //将新的文件描述符加入到集合中
                FD_SET(cfd,&rdset);

                //更新最大的文件描述符
                maxfd=maxfd>cfd? maxfd:cfd;

            }

            for(int i=lfd+1;i<=maxfd;i++){
                if(FD_ISSET(i,&rdset)){
                    //说明这个文件描述符对应的客户端发来了数据
                    char buf[1024]={0};
                    int len=read(i,buf,sizeof(buf));
                    if(len==-1){
                        perror("read");
                        exit(-1);
                    }else if(len==0){
                        printf("client closed..\n");
                        close(i);
                        FD_CLR(i,&rdset);
                    }else if(len>0){
                        printf("read buf:%s\n",buf);
                        write(i,buf,strlen(buf)+1);
                    }
                }
            }

        }
        
    }
    close(lfd);

    return 0;
}
相关推荐
计算机学姐2 分钟前
基于Python的高校成绩分析管理系统
开发语言·vue.js·后端·python·mysql·pycharm·django
VertexGeek3 分钟前
Rust学习(三):rust基础Ⅱ
开发语言·学习·rust
一个数据小开发9 分钟前
业务开发问题之ConcurrentHashMap
java·开发语言·高并发·map
三小尛36 分钟前
插入排序(C语言)
c语言·开发语言
七月.末39 分钟前
安卓aab包的安装教程,附带adb环境的配置
android·adb
南宫理的日知录41 分钟前
106、Python并发编程:深入浅出理解线程池的内部实现原理
开发语言·python·学习·编程学习
焦糖酒1 小时前
终端应用开发沉思录
javascript·前端框架
WolvenSec1 小时前
C/C++逆向:结构体逆向分析
c语言·开发语言·c++·网络安全
谢尔登1 小时前
前端开发调试之 PC 端调试
开发语言·前端
每天吃饭的羊1 小时前
在循环中只set一次
开发语言·前端·javascript