socket api- c/s模式:全双工 ;IO模式:同步阻塞,select,多路复用。

server:

client:

知识点:

1)服务端的多线程改为select复用来处理多用户。

  应该服务器瓶颈是在网络。CPU应该不是瓶颈,如果网络不是瓶颈,想再提高性能,可以考虑增加线程处理。

  1.标准输入可以另用线程,从select 分离出去。

  2.serverFD的accpet,也可以另用线程,分离出去。不过就要处理共享数据的tempserver的Fd集合了,加锁。所以这个感觉还是不要分离出去好。毕竟集合的添加删除是个频繁操作。

  3.多用户的处理,倒是可以用多线程处理。根据集合大小的情况。超过某个数量。就新开线程处理集合的某部分。新开的线程明显应该从某个数量检测,而select要从0开始检测fd,这个倒是浪费性能的事情。

未处理点:

1)还是要分行进行任务的处理。

#include <iostream>
#include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET
#include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>//perror
#include <fcntl.h>
#include <unistd.h>//close.
#include <time.h>
#include <arpa/inet.h>//INET_PTON
#include <chrono>
#include <vector>
#include <algorithm>

using namespace std;

const int MAXLINE=1024*4;

typedef struct sockaddr_in SA;
string g_cmd;

void Accpetthread(int serverFD);
void threadProcess(int serverTempFD);
int main()
{
    //socket->addr->bind->listen->accept(read ,write)
    int serverFD;
    int intflag;
    g_cmd="";
    SA serverAddr;
    bzero(&serverAddr,sizeof(serverAddr));
    serverFD=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
    if(serverFD==-1)
    {
        perror("create()");
        return -1;
    }

    //serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr);
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(3007);
    //serverAddr.sin_zero??

    intflag=bind(serverFD,(sockaddr*)&serverAddr,sizeof(sockaddr));
    if(intflag==-1)
    {
        perror("bind()");
        return -1;
    }

    listen(serverFD,10);//max queue?

    string cmd;
    cout<<"exist:input 88"<<endl;

    //stdin->cmd  .socket->read&write. socket -> accept.

    fd_set fdset;
    int maxsocketFD=serverFD>STDIN_FILENO?serverFD+1:serverFD+1;

    vector<int> fdArrays;

    while(true)
    {

        FD_ZERO(&fdset);
        FD_SET(serverFD,&fdset);
        FD_SET(STDIN_FILENO,&fdset);

        //int max_id= max_element(fdArrays.begin(),fdArrays.end());

        for(int tempfdid: fdArrays)
        {
            FD_SET(tempfdid,&fdset);
            maxsocketFD=maxsocketFD>tempfdid?maxsocketFD:tempfdid+1;

            SA peerSA;
            socklen_t slen;
            int gresult= getpeername(tempfdid, (sockaddr*)&peerSA,&slen);
            if(gresult==-1)
            {
                perror("getpeername");
            }
            else
            {
                cout<<peerSA.sin_port<<endl;
            }

        }

        select(maxsocketFD,&fdset,0,0,0);

        if(FD_ISSET(STDIN_FILENO,&fdset))
        {
            cin>>cmd;
            if(cmd=="88")
            {
                close(serverFD);
                break;
            }
        }

        if(FD_ISSET(serverFD,&fdset))
        {
            //accept.& save it to array.
            int serverTempFD=accept(serverFD,0,0);
            if(serverTempFD==-1)
            {
                perror("accept");
            }
            else
            {
                fdArrays.push_back(serverTempFD);
            }
        }

        for(int tempfdid: fdArrays)
        {
            if(FD_ISSET(tempfdid,&fdset))
            {
                char readbuf[MAXLINE];
                bzero(readbuf,MAXLINE);
                int sizeread= read(tempfdid,readbuf,MAXLINE-1);
                if(sizeread==-1)//-1到底是个什么状态?是彻底不能连接还是可以重试?
                {
                    perror("read");
                    fdArrays.erase(find(fdArrays.begin(),fdArrays.end(),tempfdid));
                    close(tempfdid);
                    break;
                }
                else if(sizeread==0)//peer close or shutdown wr.
                {
                    fdArrays.erase(find(fdArrays.begin(),fdArrays.end(),tempfdid));
                    close(tempfdid);
                    break;
                }
                else
                {
                    readbuf[sizeread]=‘\0‘;//以免溢出,插入结束符号.
                    char writebuff[MAXLINE+10];
                    //snprintf如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符(‘\0‘)
                    snprintf(writebuff,MAXLINE+10-1,"%s:%d\n",readbuf,strlen(readbuf));
                    cout<<writebuff<<flush;
                    write(tempfdid,writebuff,strlen(writebuff));
                }
            }
        }
    }
    return 0;
}

client:

#include <iostream>
#include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET
#include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>//perror,fgets
#include <fcntl.h>
#include <unistd.h>//close.
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>//INET_PTON
#include <string>

const int MAXLINE=1024*4;

using namespace std;

int main()
{

    //socket->connect->read.
    int socketClientFD;
    int statusFlag;

    socketClientFD=socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
    if(socketClientFD==-1)
    {
        perror("socket()");
        return -1;
    }

    struct sockaddr_in serverAddr;
    bzero(&serverAddr,sizeof(serverAddr));
    serverAddr.sin_family=AF_INET;
    inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr);

    //printf("%0x,%0x,%0x,%0x",((char*)&serverAddr.sin_addr)[0],((char*)&serverAddr.sin_addr)[1],((char*)&serverAddr.sin_addr)[2],((char*)&serverAddr.sin_addr)[3]);

    serverAddr.sin_port=htons(3007);

    statusFlag=connect(socketClientFD,(sockaddr*)&serverAddr,sizeof(serverAddr));

    if(statusFlag==-1)
    {
        perror("connect()");
        return -1;
    }

    char writeChar[MAXLINE];
    char buff[MAXLINE];

    fd_set fdset;//定义描述符集。

    FD_ZERO(&fdset);//初始化描述符集。

    int endflag=0;

    while(true)
    {
        //1)如果没有会触发很多次shutdown(socketClientFD,SHUT_WR);。,并且导致服务端,read 的时候会收到-1.
        //这样直接就关闭connect。客户端可能读不到任何数据。
        //2)为什么每次都要重新设置?
        if(endflag==0)
        {
            FD_SET(STDIN_FILENO,&fdset);//打开标准输入bit位。
        }
        else
        {
            FD_CLR(STDIN_FILENO,&fdset);//与其后面取消。还不如根绝标志这里设置。这样还统一一点。代码更清晰.
        }
        FD_SET(socketClientFD,&fdset);//打开客户socket bit位。

        int maxCheckFDCount=socketClientFD>STDIN_FILENO?socketClientFD+1:STDIN_FILENO+1;//只有2个描述符,肯定是除标准外的那个+1.

        select(maxCheckFDCount,&fdset,0,0,0);//只关心接收描述符。

        if(FD_ISSET(STDIN_FILENO,&fdset))
        {
            //cin.getline(writeChar,MAXLINE);
            bzero(writeChar,MAXLINE);

            cout<<"stdin fire"<<endl;

            int n=read(STDIN_FILENO,writeChar,MAXLINE);
            if(n==0)
            {
                cout<<"wirte over"<<endl;
                shutdown(socketClientFD,SHUT_WR);
                endflag=1;
                //close(socketClientFD);
            }
            else
            {

                statusFlag= write(socketClientFD,writeChar,strlen(writeChar));//写的时候只发送字符。不发送结束符。所以用strlen.

                if(statusFlag==-1)
                {
                    perror("write()");
                    return -1;
                }
            }
        }

        if(FD_ISSET(socketClientFD,&fdset))
        {
            bzero(buff,MAXLINE);
            statusFlag=read(socketClientFD,buff,MAXLINE-1);
            cout<<"start read"<<endl;
            if(statusFlag==0)//非正常关闭。因为这个cs模式下,服务端是被动关闭。程序是不可能得到0的。只有客户端close后才会由内核得到0.
            {
                cout<<"server close."<<endl;
                //close(socketClientFD);//到这里关闭。
                break;
            }
            else if(statusFlag==-1)
            {
                perror("read()");
                return -1;
            }
            else
            {
                buff[statusFlag]=‘\0‘;
                cout<<buff<<flush;
            }
        }
    }
    return 0;
}
时间: 2024-11-03 22:41:07

socket api- c/s模式:全双工 ;IO模式:同步阻塞,select,多路复用。的相关文章

异步IO比同步阻塞IO性能更好吗?为什么?

最近在看node.js, 介绍中提到node是异步io的方式实现, 性能比同步阻塞io的更好. 对于一个request而言, 如果我们依赖io的结果, 异步io和同步阻塞io都是要等到io完成才能继续执行. 而同步阻塞io, 一旦阻塞就不会在获得cpu时间片, 那么为什么异步的性能更好呢? 这个问题之前在做Servlet AIO优化的时候就没想太明白. 现在回想起来tomcat这类server的NIO并发数是有瓶颈的, 即便是空跑也只能到1000个并发量级, 而Nginx可以做到C10k. 问题

Linux五种IO模型(同步 阻塞概念)

Linux五种IO模型 同步和异步 这两个概念与消息的通知机制有关. 同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.比如,调用readfrom系统调用时,必须等待IO操作完成才返回. 异步 异步的概念和同步相对.当一个异步过程调用发出后,调用者不能立刻得到结果.实际处理这个调用的部件在完成后,通过状态.通知和回调来通知调用者.比如:调用aio_read系统调用时,不必等IO操作完成就直接返回,调用结果通过信号来通知调用者. 阻塞与非阻塞 阻塞与非阻塞与等待消息通知

[Z] linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO

原文链接:http://blog.csdn.net/colzer/article/details/8169075 IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descriptor(fd,文件描述符).而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符).描述符就是一个数字,指向内核中一个结构体(文件路径,数据

linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descriptor(fd,文件描述符).而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符).描述符就是一个数字,指向内核中一个结构体(文件路径,数据区,等一些属性).那么我们的应用程序对文件的读写就通过对描述符的读写完成. linux将内存分为内核区,用户区.l

高性能IO设计模式之阻塞/非阻塞,同步/异步解析

提到高性能,我想大家都喜欢这个,今天我们就主要来弄明白在高性能的I/O设计中的几个关键概念,做任何事最重要的第一步就是要把概念弄的清晰无误不是么?在这里就是:阻塞,非阻塞,同步,异步. OK, 现在来具体看看. 1. 阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值. 2. 同步和异步是针对应用程序和内核的交互而言的,同步指的是用

Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select poll epoll udp组播 线程池

[本文谢绝转载原文来自http://990487026.blog.51cto.com] Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select  poll  epoll udp组播 线程池 TCP 11种状态理解: 1,客户端正常发起关闭请求 2,客户端与服务端同时发起关闭请求 3,FIN_WAIT1直接转变TIME_WAIT 4,客户端接收来自服务器的关闭连接请求 多路IO转接服务器: select模型 poll模型 epoll模型 udp组播模型 线

Linux IO模式及 select、poll、epoll详解

注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. 一 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进程的阻塞 - 文件描述符 - 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32

Linux IO模式

原文地址:https://segmentfault.com/a/1190000003063859 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. 一 概念说明 在进行解释之前,首先要说明几个概念: 用户空间和内核空间 进程切换 进程的阻塞 文件描述符 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的

(转)Linux IO模式及 select、poll、epoll详解

本文为转载,并作了部门调整.修改. [原文出处:https://segmentfault.com/a/1190000003063859] 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. 一 概念说明 在进行解释之前,首先要说明几个概念: 用户空间和内核空间 进程切换 进程的阻塞 文件描述符 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O 五种I/O 模式:[1]        阻塞 I/O           (Linux下的I/O操作默认是阻塞I/O,即open和socket创建的I/O都是阻塞I/O)[2]        非阻塞 I/O        (可以通过fcntl或者open时使用O_NONBLOCK参数,将fd设置为非阻塞的I/O)[3]        I/O 多路复用     (I/O