我就搞不懂了,这个socket的select模式和常规阻塞式的socket有什么本质区别

feng2ge1 2014-06-03 02:15:00
最常规的socket,阻塞就是被停留在accept那里, 但是我看select的这种一样也是被阻塞在一个while 循环里面啊,一样跳不出那个循环,后面的也执行不了,也是一样几乎除了建立链接之外其他啥都干不了啊, 有什么本质区别, 看不出有多大优势啊
...全文
153 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2014-06-03
  • 打赏
  • 举报
回复
http://bbs.csdn.net/topics/390374955 参考X:\MSDN98_1\SAMPLES\VC98\SDK\NETDS\WINSOCK\SIMPLE\IOCTL.C
/******************************************************************************\
* ioctl.c - TCP server
*
*       This is a part of the Microsoft Source Code Samples.
*       Copyright 1996-1997 Microsoft Corporation.
*       All rights reserved.
*       This source code is only intended as a supplement to
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the
*       Microsoft samples programs.
\******************************************************************************/



#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 5001

int ReadAndEcho(SOCKET , char *,int ) ;
int WriteMessage(SOCKET , char *,int ) ;

void Usage(char *progname) {
    fprintf(stderr,"Usage\n%s -e [endpoint] -i [interface]\n",
        progname);
    fprintf(stderr,"Where:\n");
    fprintf(stderr,"\tendpoint is the port to listen on\n");
    fprintf(stderr,"\tinterface is the ipaddr (in dotted decimal notation)");
    fprintf(stderr," to bind to\n");
    fprintf(stderr,"Defaults are 5001 and INADDR_ANY\n");
    WSACleanup();
    exit(1);
}
int main(int argc, char **argv) {

    char Buffer[128];
    char *interface= NULL;
    unsigned short port=DEFAULT_PORT;
    int fromlen;
    int i, ioctl_opt =1;
    struct sockaddr_in local, from;
    WSADATA wsaData;
    SOCKET listen_socket, msgsock;
    fd_set readfds, writefds, exceptfds;

    /* Parse arguments */
    if (argc >1) {
        for(i=1;i <argc;i++) {
            if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
                switch(tolower(argv[i][1])) {
                    case 'i':
                        interface = argv[++i];
                        break;
                    case 'e':
                        port = atoi(argv[++i]);
                        break;
                    default:
                        Usage(argv[0]);
                        break;
                }
            }
            else
                Usage(argv[0]);
        }
    }

    if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
        fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }

    if (port == 0){
        Usage(argv[0]);
    }

    //
    // The fd sets should be zeroed out before using them to prevent errors.
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_ZERO(&exceptfds);
    memset(Buffer,0,sizeof(Buffer));

    local.sin_family = AF_INET;

    //
    // bind to specific interface if desired.

    local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface);

    /*
     * Port MUST be in Network Byte Order
     */
    local.sin_port = htons(port);

    listen_socket = socket(AF_INET, SOCK_STREAM,0); // TCP socket
    if (listen_socket == INVALID_SOCKET){
        fprintf(stderr,"socket() failed with error %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }
    //
    // bind() associates a local address and port combination with the
    // socket just created.

    if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) )
        == SOCKET_ERROR) {
        fprintf(stderr,"bind() failed with error %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }

    //
    // start listening on the socket for incoming connections
    //
    if (listen(listen_socket,5) == SOCKET_ERROR) {
        fprintf(stderr,"listen() failed with error %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }
    printf("%s: Listening on port %d\n",argv[0],port);

    //
    // Set the socket to non-blocking mode.
    //
    if (ioctlsocket(listen_socket,FIONBIO,&ioctl_opt) == SOCKET_ERROR) {
        fprintf(stderr,"ioctlsocket failed %d\n",WSAGetLastError());
        WSACleanup();
        return -1;
    }
    //
    // The structure of the loop below is very simple. We only accept one
    // connection at a time. As soon as another client connects, we
    // disconnect the first one, and start talking to the new client.
    // All this server does is to echo the data received on the socket
    // back to the client.
    //
    // This is not a very realistic server, but it does serve to show that
    // select() does not scale very well on win32. If we were dealing
    // with more than one client, we would have to have a list of sockets
    // that are in each fdset to be able to check them when select()
    // returns.
    //
    while(1) {

        //
        // A socket in the listen() state becomes ready to read when a
        // client connects to it. An accept() will complete without
        // blocking.
        // Since select sets the sockets that are ready to be read from or
        // written to, we have to include listen_socket in the fdset each time
        // through the loop.
        //

        FD_SET(listen_socket,&readfds);

        i = select(0,&readfds,&writefds,&exceptfds,NULL);
        if (i == SOCKET_ERROR) {
            fprintf(stderr,"select failed %d\n",WSAGetLastError());
        }
        if (i==0){
            fprintf(stderr,"Select returned no fds ready\n");
        }

        if (FD_ISSET(listen_socket, &readfds)){
            //
            // close the previous client socket.
            // We must also clear it from the fdset to prevent select()
            // from failing.
            //
            closesocket(msgsock);
            FD_CLR(msgsock,&readfds);
            FD_CLR(msgsock,&writefds);
            fromlen = sizeof(from);
            msgsock= accept(listen_socket,(struct sockaddr*)&from,&fromlen);
            if (msgsock == INVALID_SOCKET) {
                fprintf(stderr,"accept failed %d\n",WSAGetLastError());
                WSACleanup();
                return -1;
            }
            FD_SET(msgsock,&writefds);
            FD_SET(msgsock,&readfds);
            continue;
        }
        if (FD_ISSET(msgsock,&readfds) ) {
            //
            // socket is ready to read, i.e., there is data on the socket.
            //
            if (ReadAndEcho(msgsock,Buffer,sizeof(Buffer))<0) {
                fprintf(stderr,"terminating connection\n");
                FD_CLR(msgsock,&readfds);
                FD_CLR(msgsock,&writefds);
                closesocket(msgsock);
                continue;
            }
        }
        if (FD_ISSET(msgsock,&writefds) ){
            if (WriteMessage(msgsock,Buffer,sizeof(Buffer)) <=0) {
                fprintf(stderr,"terminating connection\n");
                FD_CLR(msgsock,&readfds);
                FD_CLR(msgsock,&writefds);
                closesocket(msgsock);
                continue;
            }
        }
        FD_SET(msgsock,&writefds);
        FD_SET(msgsock,&readfds);
    }
}
int ReadAndEcho(SOCKET insock, char *Buffer,int size) {
    int rc;

    rc = recv(insock,Buffer,size,0);

    if (rc == SOCKET_ERROR) {
        fprintf(stderr,"recv() failed with error %d\n",WSAGetLastError());
        return -1;
    }
    if (rc ==0) {
        fprintf(stderr,"Connection closed by client\n");
        return 0;
    }
    printf("Received [%s] from client\n",Buffer);
    return rc;
}
int WriteMessage(SOCKET outsock, char *Buffer,int size) {
    int rc;
    int lasterr;

    printf("Sending [%s] to client\n",Buffer);
    rc = send(outsock,Buffer,size, 0);

    if (rc == SOCKET_ERROR) {
      lasterr = WSAGetLastError();
      if (lasterr == WSAEWOULDBLOCK)
        return 0;
      else {
        fprintf(stderr,"send() failed with error %d\n",lasterr);
        return -1;
      }
    }
    if (rc ==0) {
        fprintf(stderr,"Connection closed by client\n");
    }
    return rc;
}
帅得不敢出门 2014-06-03
  • 打赏
  • 举报
回复
有机会建议看看select的实现
baichi4141 2014-06-03
  • 打赏
  • 举报
回复
"我看select的这种一样也是被阻塞在一个while 循环里面" 楼主你看的代码一定很神奇
  • 打赏
  • 举报
回复
区别很多,例如,select可以设置超时,再例如,select可以在一个线程内完成accept、recv和send的工作
ztenv 版主 2014-06-03
  • 打赏
  • 举报
回复
select可以在一个线程中同时等多个socket

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧