select 服务器 客户端 缩水版

哈希蝉翼
• 阅读 1730

tcpserver.c

int main(int argc, char**argv)
{
    int listenfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serv_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    memset(&serv_addr,0,sizeof(serv_addr));
    memset(&client_addr,0,sizeof(client_addr));
    
    serv_addr.sin_addr.s_addr = INADDR_ANY; //绑定所有ip
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port = htons(PORT);
    int opt = 1;
    socklen_t  optlen = sizeof(opt);
    
    //设置复用ip
    if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,optlen) < 0){
        perror("setsockopt");
        return  0;
    }
 
    //设置ip port
    if(bind(listenfd,(SA*)&serv_addr,sizeof(serv_addr)) < 0){
        perror("bind");
        return 0;
    }
    
    //BACKLOG = 10
    if(listen(listenfd,BACKLOG) < 0){
        perror("listen");
        return 0;
    }
    
    //一些变量,下面会用到
    int nready = 0,client[FD_SETSIZE] , maxfd = listenfd , connfd = 0,maxi = -1;
    
    // client 用于存储 客户描述符
    for(int i = 0; i < FD_SETSIZE ; ++i)
        client[i] = -1;
    fd_set rset ,allset;
    FD_ZERO(&allset);
    
    //把监听套接字先置位
    FD_SET(listenfd,&allset);
    int clientfd = -1 , n = 0 , i = 0;
    char buf[BUFSIZ];
    while(1){
        //select 每次将修改rset,需要重置
        rset = allset;
        nready = select(maxfd+1,&rset,NULL,NULL,NULL);
        printf("nread : %d \n" , nready);
        
        //可能被信号打断
        if(nready < 0){
            perror("select");
            continue;
        }
        //客户链接 进来
        if(FD_ISSET(listenfd,&rset)){
            client_len = sizeof(client_addr);
            connfd = accept(listenfd,(SA*)&client_addr,&client_len);
            printf("a client : %d\n" , connfd);
            
            //找个位置放进去
            for(i = 0; i < FD_SETSIZE; ++i){
                if(client[i] < 0) {
                    client[i] = connfd;
                    break;
                }
            }
            //服务器已满
            if(FD_SETSIZE == i){
                close(connfd);
                puts("server is full");
            }
            else {
                
                //把客户fd 放入监听集合中
                FD_SET(connfd,&allset);
                if(connfd > maxfd)
                    maxfd = connfd;
                //client 索引
                if( i > maxi)
                    maxi = i;
                //如果数量为0 则不需要往下继续了
                if(--nready == 0)
                    continue;
            }
        }
        
        for(int i = 0 ; i <= maxi;++i){
            
            if((clientfd = client[i]) <0 )
                continue;
            
            //直到找到一个可读的fd
            if(FD_ISSET(clientfd,&rset)){
                printf("clientfd : %d is ready\n", clientfd);
                
                //如果对断关闭了 
                if((n = read(clientfd,buf,BUFSIZ)) <= 0){
                    printf("clientfd : %d closed\n",clientfd);
                    //清空当前fd 所存在的地方
                    close(clientfd);
                    FD_CLR(clientfd,&allset);
                    client[i] = -1;
                } else{
                    write(clientfd,buf,n);
                }
                if(--nready == 0)
                    break;
            }
        }
    }
 
 
    return 0;
}

tcpclient.c

 
 
void str_echo(int sockfd);
int max(int a, int b){
    return a > b ? a : b;
}
int main(int argc, char**argv)
{
    if(argc != 2){
        puts("ip addr");
        return 0;
    }
 
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in sin;
    memset(&sin,0,sizeof(sin));
    sin.sin_port = htons(PORT);
    sin.sin_family = AF_INET;
 
    //把字符串转成网络字节序
    inet_pton(AF_INET,argv[1],&sin.sin_addr);
 
    connect(sockfd,(SA*)&sin,sizeof(sin));
    str_echo(sockfd);
 
    return 0;
}
 
void str_echo(int sockfd){
    int maxfd = sockfd;
    int eof = 0 , readn = 0 , fd_num = 0, n= 0;
    char buf[BUFSIZ];
    fd_set rset;
    FD_ZERO(&rset);
 
    while(1)
    {
        //EOF ==》 CTRL+D
        if(0 == eof){
            FD_SET(0,&rset);
        }
 
        //select 将修改rset ,每次重置
        FD_SET(sockfd,&rset);
        maxfd = max(0,sockfd);
        fd_num = select(maxfd+1,&rset,NULL,NULL,NULL);
        printf("fd_num : %d\n" , fd_num);
 
        //如果是套接字可读
        if(FD_ISSET(sockfd,&rset)){
            //服务器关闭
            if((n=read(sockfd,buf,BUFSIZ)) <= 0){
                if(eof == 1){
                    puts("server closed");
                    break;
                }
                else {
                    puts("server ter");
                    break;
                }
 
            }
            buf[n] = 0;
            printf("recv from serv:%s\n" , buf);
        }
 
        //如果是输入端可读
        if(FD_ISSET(0,&rset)){
 
            //如果ctrl + d
            if((n = read(0,buf,BUFSIZ)) <= 0){
                printf("client closing\n");
 
                //先发送Fin , 等服务端close
                shutdown(sockfd,SHUT_WR);
                eof = 1;
                FD_CLR(0,&rset);
                continue;
            }
            write(sockfd,buf,n);
        }
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
C# Aspose.Cells导出xlsx格式Excel,打开文件报“Excel 已完成文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃”
报错信息:最近打开下载的Excel,会报如下错误。(xls格式不受影响)!(https://oscimg.oschina.net/oscnet/2b6f0c8d7f97368d095d9f0c96bcb36d410.png)!(https://oscimg.oschina.net/oscnet/fe1a8000d00cec3c
Stella981 Stella981
3年前
Linux查看GPU信息和使用情况
1、Linux查看显卡信息:lspci|grepivga2、使用nvidiaGPU可以:lspci|grepinvidia!(https://oscimg.oschina.net/oscnet/36e7c7382fa9fe49068e7e5f8825bc67a17.png)前边的序号"00:0f.0"是显卡的代
Wesley13 Wesley13
3年前
TCP 远程执行CMD (解决粘包问题) 代码
服务端1fromsocketimport2importsubprocess,json,struct34serversocket(AF_INET,SOCK_STREAM)5server.bind(('127.0.0.1',8081))6server.listen
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
ClickHouse性能提升
本文经作者授权,独家转载:作者主页:https://www.jianshu.com/u/8f36a5e63d181\.不要用select\反例:select  from app.user_model正例:select login_id,name,sex from app.user_mo
Stella981 Stella981
3年前
Github标星5300+,专门为程序员开发文档开源管理系统,我粉了
!(https://oscimg.oschina.net/oscnet/a11909a041dac65b1a36b2ae8b9bcc5c432.jpg)码农那点事儿关注我们,一起学习进步!(https://oscimg.oschina.net/oscnet/f4cce1b7389cb00baaab228e455da78d0
哈希蝉翼
哈希蝉翼
Lv1
在天愿作比翼鸟,在地愿为连理枝。
文章
3
粉丝
0
获赞
0