首页 > Windows开发 > 详细

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

时间:2017-02-03 13:35:54      阅读:423      评论:0      收藏:0      [点我收藏+]

server:

未处理点:

1)pollfd 数组,应该设置一个有效总数,当fd最大有效索引值> 有效总数=某个比较值,那么应该执行数据压缩.

2)socket的有效超时是设定阻塞的.有没有方法.设置一个socket.的有效时?超过多少时间,无事件发生就关闭?还是需要自己处理.那么就应该自己多加一个值来记录每个socket的非活跃时间了.

 

#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>
#include <poll.h>

using namespace std;

const int MAXLINE=1024*4;
const int MAXFD=100;

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(3013);
    //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.
    //serverfd,stdin.
    //tempfd.
    //struct pollfd. poll()
//    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//
//       #define _GNU_SOURCE         /* See feature_test_macros(7) */
//       #include <signal.h>
//       #include <poll.h>
    struct pollfd pollfdArray[MAXFD];
    pollfdArray[0].fd=STDIN_FILENO;
    pollfdArray[0].events=POLLIN;//标准输入数据不是普通数据......
    pollfdArray[0].revents=0;

    pollfdArray[1].fd=serverFD;
    pollfdArray[1].events=POLLRDNORM;//标准输入数据不是普通数据......
    pollfdArray[1].revents=0;

    int fdMAXIndex=1;

    for(int i=2;i<MAXFD;++i)
    {
        pollfdArray[i].fd=-1;
    }

    while(true)
    {
        int pollStatus= poll(pollfdArray,fdMAXIndex+1,-1);
        if(pollStatus<0)
        {
            perror("poll()");
        }
        else if(pollStatus==0)
        {
            cout<<"no events. why program be here?"<<endl;
        }
        else
        {
            if(pollfdArray[1].revents==POLLRDNORM)
            {
                pollfdArray[1].revents=0;
                int tempServerFD=accept(pollfdArray[1].fd,0,0);//-1或非负整数

                if(tempServerFD==-1)
                {
                    perror("accept()");
                }
                for(int i=2;i<MAXFD;++i)
                {
                    if(pollfdArray[i].fd==-1)
                    {
                        pollfdArray[i].fd=tempServerFD;
                        pollfdArray[i].events=POLLRDNORM;

                        fdMAXIndex=fdMAXIndex>i?fdMAXIndex:i;
                        break;//
                    }

                }
                if(--pollStatus<=0)
                {
                    continue;
                }
            }


            for(int i=2;i<=fdMAXIndex&&pollStatus>0  ;++i)
            {
                if(pollfdArray[i].fd!=-1)
                {
                    if(pollfdArray[i].revents==POLLRDNORM)
                    {
                        char readbuf[MAXLINE];
                        bzero(readbuf,MAXLINE);
                        int sizeread= read(pollfdArray[i].fd,readbuf,MAXLINE-1);
                        if(sizeread==-1)//-1到底是个什么状态?是彻底不能连接还是可以重试?
                        {
                            perror("read()");
                            close(pollfdArray[i].fd);
                            pollfdArray[i].fd=-1;
                        }
                        else if(sizeread==0)
                        {
                            close(pollfdArray[i].fd);
                            pollfdArray[i].fd=-1;
                        }
                        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(pollfdArray[i].fd,writebuff,strlen(writebuff));
                        }
                        --pollStatus;
                    }
                }
            }


            if(pollfdArray[0].revents==POLLIN)
            {
                pollfdArray[0].revents=0;//需要重设返回值不?

                cin>>cmd;
                if(cmd=="88")
                {
                    //close all sockets.
                    close(serverFD);
                    break;
                }
            }

        }
    }







//
//    while(true)
//    {
//
//        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(3013);


    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;
}

 

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

原文:http://www.cnblogs.com/lsfv/p/6362441.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!