惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
博客园 - 叶小钗
AI
AI
T
Tor Project blog
Forbes - Security
Forbes - Security
W
WeLiveSecurity
博客园_首页
爱范儿
爱范儿
J
Java Code Geeks
B
Blog
G
GRAHAM CLULEY
aimingoo的专栏
aimingoo的专栏
Cloudbric
Cloudbric
C
CXSECURITY Database RSS Feed - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Simon Willison's Weblog
Simon Willison's Weblog
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
H
Help Net Security
博客园 - 三生石上(FineUI控件)
C
Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
The Last Watchdog
The Last Watchdog
Blog — PlanetScale
Blog — PlanetScale
T
The Blog of Author Tim Ferriss
S
Secure Thoughts
Spread Privacy
Spread Privacy
F
Fortinet All Blogs
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog

浮生笔记

时机的重要性 回答dayu博客的几个问题 学会做选择 我理想的城市 如何选择一个适合的城市 马来西亚游记 回首2023,展望2024 从ChatGPT聊起 菲律宾旅游攻略笔记 深圳游记 香港游记 怎样赚钱----我理解的商业模式 用户界面与跨平台 使用telnet通过IMAP协议读取QQ邮箱 信息成本-----从ChatGPT到情报学 买断制到订阅制----兼谈消费频次 我眼中的CSDN 迁移博客内容到静态博客 Hugo使用Jane主题支持搜索实现 C语言和Lua的相互调用示例代码 从放逐之城看经济学 不同产业的分析 回首2021,展望2022 游戏中的经济学 Windows获取网络地址、子网掩码等 -fsanitize=address 参数作用 C++ 编译器支持标准判断 C++ 编译器支持标准判断 VS Code的golang开发配置 之 代码提示 二叉树遍历的非递归算法的实现 我的Chrome插件 golang 获取get参数 关于写代码的几个看法 golang编程之我见 构建之法读书笔记 (1) 友情链接 Effective Morden C++ 读书笔记(3) 二进制协议 vs 文本协议 从重构到重写 asio制作使用ssl通信的证书 gdb 7.11 Linux 获取网卡信息 《构建之法》读后感 由买冰箱想到的 2014年年终总结 聊聊我对写好程序的认识 编程技巧之表格驱动编程 经验搜索排名---google已经做过类似的了(我想多了) 有关编程语言的认识
Linux 网络编程之 Select
DennisThink · 2017-11-20 · via 浮生笔记
/*server*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <stdlib.h>
#include "common.h"
#include <iostream>
void process_cli(Client *client, char* recvbuf, int len,int count);  //客户请求处理函数
int main(int argc,char * argv[])
{
    int listenFd=0;
    //地址信息结构体大小
    if ((listenFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {    //调用socket创建用于监听客户端的socket
        std::cout<<"Creating socket failed."<<std::endl;
        exit(1);
    }

    int opt = SO_REUSEADDR;
    setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    //设置socket属性

    struct sockaddr_in serverAddr;     //服务器地址信息结构体
    bzero(&serverAddr,sizeof(serverAddr));
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(PORT);
    serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
    if (bind(listenFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) {    //调用bind绑定地址
        std::cout<<"Bind error."<<std::endl;
        exit(1);
    }

    if(listen(listenFd,BACKLOG) == -1) {
        //调用listen开始监听
        std::cout << "listen() error"<<std::endl;
        exit(1);
    }


 
    Client client[FD_SETSIZE];     //FD_SETSIZE为select函数支持的最大描述符个数
    char recvbuf[MAXDATASIZE];    //缓冲区
    int sin_size=sizeof(struct sockaddr_in);
    //初始化select
    int maxI;
    int maxFd;
    int sockfd;
    int    nReady;
    ssize_t      n;
    fd_set readSet;//可读socket的文件描述符的集合
    fd_set allSet;//所有socket的文件描述符的集合
    for (int i = 0; i < FD_SETSIZE; i++) {
        client[i].fd = -1;
    }
    maxFd= listenFd;
    FD_ZERO(&allSet);        //清空
    FD_SET(listenFd, &allSet);    //将监听socket加入select检测的描述符集合

    int connectFd=0;     //socket文件描述符
    int clientCount=0;
    while(1)
    {
        struct sockaddr_in addr;
        readSet = allSet;
        nReady = select(maxFd+1, &readSet, NULL,NULL, NULL);    //调用select
        if (FD_ISSET(listenFd, &readSet)) {      //检测是否有新客户端请求
            //调用accept,返回服务器与客户端连接的socket描述符
            if ((connectFd = accept(listenFd,(struct sockaddr *)&addr,(socklen_t *)&sin_size))==-1) {
                std::cout<<"accept() error"<<std::endl;
                continue;
            }

            //将新客户端的加入数组
            int i = 0;
            for (int i = 0; i < FD_SETSIZE; i++) {
                if (client[i].fd < 0) {
                    client[i].fd = connectFd;    //保存客户端描述符
                    char addrBuf[32];
                    sprintf(addrBuf,"%s:%d",inet_ntoa(addr.sin_addr),addr.sin_port);
                    clientCount++;
                    client[i].m_addr=std::string(addrBuf);
                    break;
                }
            }
            if (i == FD_SETSIZE)
            {
                std::cout<<"too many clients"<<std::endl;
            }
            if (i > maxI)          //数组最大元素值
            {
                maxI = i;
            }
            FD_SET(connectFd, &allSet);   //将新socket连接放入select监听集合
            if (connectFd > maxFd)
            {
                maxFd = connectFd;   //确认maxfd是最大描述符
            }

            if (--nReady <= 0)
            {
                continue;      //如果没有新客户端连接,继续循环
            }
        }

        for (int i = 0; i <= maxI; i++) 
        {
            if ( (sockfd = client[i].fd) < 0)       //如果客户端描述符小于0,则没有客户端连接,检测下一个
            { 
                continue;
            }
            if (FD_ISSET(sockfd, &readSet)) 
            {        //检测此客户端socket是否有数据
                int nReadLength = recv(sockfd, recvbuf, MAXDATASIZE,0);
                if (nReadLength == 0) 
                { //从客户端socket读数据,等于0表示网络中断
                    close(sockfd);        //关闭socket连接
                    FD_CLR(sockfd, &allSet);    //从监听集合中删除此socket连接
                    client[i].fd = -1;        //数组元素设初始值,表示没客户端连接
                    std::cout<<"Client Addr: "<< client[i].m_addr << " Close "<<std::endl;
                    clientCount--;
                } 
                else
                {
                    process_cli(&client[i], recvbuf, nReadLength,clientCount);    //接收到客户数据,开始处理
                }
                if (--nReady <= 0)
                {
                    break;       //如果没有新客户端有数据,跳出for循环回到while循环
                }  
            }
        }
    }
    close(listenFd);  //关闭服务器监听socket
}

void process_cli(Client *client, char* recvbuf, int len,int count)
{
    char sendbuf[MAXDATASIZE];
    OctArray16 * recvData = (OctArray16*)recvbuf;
    std::cout<<"RecvData From Client:"<< client->m_addr <<"   Data:"<<recvData->toString()<<std::endl;
    sprintf(sendbuf,"%d--%s",count,GetCurrentTime().c_str());
    OctArray16 sendData(sendbuf);
    send(client->fd,&sendData,sendData.size(),0);
}
/* client */
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
#include "common.h"


int main(int argc, char *argv[])
{
    char hostname[100];
    gethostname(hostname,sizeof(hostname));
    int sockfd, numbytes;

    struct hostent *he;
    struct sockaddr_in serv_addr;
    if ((he = gethostbyname(defaultHostName)) == NULL)
    {
        std::cout<<"gethostbyname error!"<<std::endl;
        return 0;;
    }
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        std::cout<< "socket error!"<<std::endl;
        return 0;
    }
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(serv_addr.sin_zero), 8);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
    {
        std::cout<<"connect error!"<<std::endl;
        return 0;
    }
    pid_t pId= getpid();
    char SendBuf[16];

    srand(time(0));
    char buf[MAXDATASIZE];
    for(int x = 0 ; x < 10 ; x++) {
        sleep(rand()%10);
        sprintf(SendBuf,"%d",pId);
        OctArray16 sendData(SendBuf);
        if ((numbytes = send(sockfd,&sendData,sendData.size(),0)) != -1)
        {
            if ((numbytes = read(sockfd, buf, MAXDATASIZE)) == -1)
            {
                std::cout<<"read error!\n"<<std::endl;
                return 0;
            }
            OctArray16 * RecvData = (OctArray16*)buf;
            std::cout<<"Client  "<< pId <<"  Recv: "<<RecvData->toString()<<std::endl;
        }
    }
    close(sockfd);       
}
/*common.h*/
#ifndef COMMON_H_
#define COMMON_H_
const int PORT=2248;           //服务器端口
const int BACKLOG=5;           //listen队列中等待的连接数
const int MAXDATASIZE=1024;    //缓冲区大小
const char defaultHostName[] = "127.0.0.1";
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <time.h>
#include <string.h>
struct Client {       //客户端结构体
    int fd;        //客户端socket描述符
    std::string m_addr;
};
class OctArray16 {
public:
    uint32_t   m_len;
    char     data[28];
    size_t size(){
        return 32;
    }
    std::string toString(){
        return std::string(data,m_len);
    }
    
    OctArray16(const char *str){
        m_len = strlen(str);
        strcpy(data,str);
    }
};

std::string GetCurrentTime(){
    time_t cutTime=time(0);
    tm * tmT=localtime(&cutTime);
    char buf[12];
    sprintf(buf,"%d:%d:%d",tmT->tm_hour,tmT->tm_min,tmT->tm_sec);
    return std::string(buf);
}
#endif
cmake_minimum_required(VERSION 2.8)

## Use the variable PROJECT_NAME for changing the target name
set( PROJECT_NAME "SelectLearn" )

## Set our project name
project(${PROJECT_NAME})

## Use all the *.cpp files we found under this folder for the project
SET(CLIENT_SOURCE Client.cpp common.h)
SET(SERVER_SOURCE Server.cpp common.h)
## Define the executable
add_executable(server ${SERVER_SOURCE})
add_executable(client ${CLIENT_SOURCE})

文章作者 DennisThink

上次更新 2017-11-20

许可协议 CC BY-NC-ND 4.0