非阻塞SOCKET中的一些问题

weixin_38305120 2017-12-05 04:03:18
在accept前,设置了ioctlsocket(sListen, FIONBIO, (u_long FAR*) &iMode),进入accept后就直接返回,需要select来判断是否成功,但是我怎么获取到客户端的SOCKET对象啊?
阻塞模式下,accept的返回值就是客户端的SCOKET对象,之前我以为fd_set可以获取到,结果发现至获取到server的SOCKET啊,求大神解析。
现在我的临时解决方案是accept还是阻塞模式,自己开条线程等待,当accept通过后再调用传入的函数指针进入recv过程,recv用了非阻塞实现,accept这部分不知道咋整。
...全文
345 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
smwhotjay 2017-12-06
  • 打赏
  • 举报
回复
想要不阻塞很简单。每次select一下它,看是否可读,是的,则可以对应读一下,保证读到数据,不会因为没数据而等待阻塞 对于listen的socket 也可以select它,可读,则说明有新连接,可以accept一下。单线程时代就靠他了,效率不高,但一千以内连接操作没问题,很多模拟器都这种模式,因为代码简单
zgl7903 2017-12-06
  • 打赏
  • 举报
回复
参考MSDN的例子

/****************************************************************************\
*  listen.c -- sample program demonstrating NWLink.
*
*       Microsoft Developer Support
*       Copyright (c) 1992-1997 Microsoft Corporation
*
*  This program is a simple example of opening a SPX socket,
*  binding to the socket, and listening for a connection.
* 
****************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <wsipx.h>
#include "../../testlib/testlib.h"

/*
*   Sockaddr structures 
*/

SOCKADDR_IPX addr;
SOCKADDR_IPX baddr;
SOCKADDR_IPX saddr;

/*
*   Function Prototypes 
*/

extern int main(int, char **);
extern int net_init(SOCKET *);
extern int do_listen(SOCKET);
extern int wait_for_connection(SOCKET, SOCKET *);
extern int do_recv_send(SOCKET);

/****************************************************************************
*
*    FUNCTION:  main( int argc, char **argv )
*
*    PURPOSE:   This is the main entry for the program
*   		    
*
*    ARGUMENTS:	argc = Number of arguments
*               argv = Array of ptrs to cmd line args
*                
*
*	 RETURNS:   Exit code for the program
*				
*\***************************************************************************/
int main(int argc, char **argv)
{
    SOCKET s, s2;

    /*
    *   Set any default values before calling parse_cmd_line 
    */

    *Local_Socket_Number = 0x05;
    *(Local_Socket_Number + 1) = 0x00;
    Socket_Type = SOCK_STREAM;
    Protocol = NSPROTO_SPX;

    /*
    *   Get any options from the command line 
    */

    parse_cmd_line(argc, argv);

    /*
    *   Initialize the network and set up our socket 
    */

    if (net_init(&s))
        return 1;

    /*
    *   Go listen for a call 
    */

    if (do_listen(s))
        return 1;

    /*
    *   Then wait for a connection 
    */

    if (wait_for_connection(s, &s2))
        return 1;

    /*
    *   Receive data then send it back 
    */

    if (do_recv_send(s2))
        return 1;

    /*
    *   All done 
    */

    if (verbose)
        printf("closing both sockets\n");

    closesocket(s2);
    closesocket(s);

    return 0;
}

/****************************************************************************
*
*    FUNCTION:  net_init( SOCKET *skt )
*
*    PURPOSE:   Initializes the WinSock stuff and sets up our socket.
*   		    
*
*    ARGUMENTS:	SOCKET * => struct to receive our socket info	
*
*	 RETURNS:   0 if ok
*				1 if error
*
*\***************************************************************************/
int net_init(SOCKET *skt)
{
    int rc, addrlen = 16;
    int non_block = 1;
    WSADATA wsdata;
    SOCKET s;
    WORD    wVersionRequested;

    wVersionRequested = MAKEWORD(1,1);

    /*
    *   Initialize with the WINSOCK library 
    */

    if (verbose)
        printf("calling WSAStartup(), ");

    rc = WSAStartup(wVersionRequested, &wsdata);

    if (verbose)
        printf("return = 0x%X, (%d)\n", rc, rc);

    if (rc) {
        printf("WSAStartup failed: error code = %d\n", rc);
        return 1;
    }

    if (verbose) {
        printf("contents of wsdata struct: \n");
        print_wsa(&wsdata);
    }

    /*
    *   Open a STREAM socket with SPX 
    */

    if (verbose)
        printf("calling socket(addresss family = %d, socket type = %d, protocol = %d)\n", Local_Address_Family, Socket_Type, Protocol);

    s = socket(Local_Address_Family, Socket_Type, Protocol);


    if (verbose)
        printf("socket() returned 0x%X (%d)\n", s, s);

    if (s == INVALID_SOCKET) {
        dos_net_perror("Socket call failed");
        exit(1);
    }

    /*
    *   Set the socket as non-blocking 
    */

    if (verbose)
        printf("Calling ioctlsocket(socket = %d, cmd = FIONBIO argp = %d), ", s, non_block);

    rc = ioctlsocket(s, FIONBIO, &non_block);

    if (verbose)
        printf("return = 0x%X (%d)\n", rc, rc);

    if (rc == SOCKET_ERROR) {
        dos_net_perror("ioctlsocket() call failed");
        closesocket(s);
        exit(1);
    }

    /*
    *   Bind to a socket.  We want to bind to a well known
    *   socket so that who ever calls us will be able to.
    */

    addr.sa_family = Local_Address_Family;
    memcpy(&addr.sa_netnum, Local_Network_Number, 4);
    memcpy(&addr.sa_nodenum, Local_Node_Number, 6);
    memcpy(&addr.sa_socket, Local_Socket_Number, 2);

    if (verbose) {
        printf("calling bind(socket = %d): \n  ", s);
        print_saddr(&addr);
    }

    rc = bind(s, (const struct sockaddr *) &addr, 16);

    if (verbose)
        printf("bind() returned 0x%X (%d)\n", rc, rc);

    if (rc == SOCKET_ERROR) {
        dos_net_perror("Error binding to socket");
        closesocket(s);
        return 1;
    }

    if (verbose)
        printf("calling getsockname(socket = %d), ", s);

    /*
    *   Get the address we bound to and print it out 
    */

    addrlen = 16;
    rc = getsockname(s, (struct sockaddr *) &baddr, &addrlen);

    if (verbose)
        printf("return = 0x%X (%d)\n", rc, rc);

    if (rc == SOCKET_ERROR) {
        dos_net_perror("Error getting socket name");
        closesocket(s);
        return 1;
    }

    /*
    *   Print out the network address 
    */

    if (verbose) {
        printf("addrlen = %d\n", addrlen);
        print_netaddr(baddr.sa_netnum, "Bound address = ", "\n");
    }

    *skt = s;

    return 0;
}

/****************************************************************************
*
*    FUNCTION:  do_listen( SOCKET s )
*
*    PURPOSE:   Sets the socket up for listening.
*
*    ARGUMENTS:	SOCKET socket to listen on
*
*	 RETURNS:   0 if ok
*				1 if error
*
*\***************************************************************************/
int do_listen(SOCKET s)
{
    int rc;

    /*
    *   Enable this socket as a listen socket that can
    *   take <Backlog> connection indication(s) at a time.
    */

    if (verbose)
        printf("calling listen(socket = %d, backlog = %d), ", s, Backlog);

    rc = listen(s, Backlog);

    if (verbose)
        printf("return = 0x%X (%d)\n", rc, rc);

    if (rc == SOCKET_ERROR) {
        dos_net_perror("listen call failed");
        closesocket(s);
        return 1;
    }

    /*
    *   Wait for a connection and get the connecting socket 
    */

    return 0;
}

/****************************************************************************
*
*    FUNCTION:  wait_for_connection( SOCKET s, SOCKET *callsock )
*
*    PURPOSE:   Waits for someone to connect.
*
*    ARGUMENTS:	SOCKET socket we are listening on
*				SOCKET * => area to store client socket info after
*				            connect	
*
*	 RETURNS:   0 if ok
*				1 if error
*
*\***************************************************************************/
int wait_for_connection(SOCKET s, SOCKET *callsock)
{
    SOCKET s2;
    int addrlen = 16;

    /*
    *   Poll the accept() call until it returns
    *   something other than WSAEWOULDBLOCK
    *   We will print out little '.' while we wait.
    */

    if (verbose)
        printf("Polling socket every 1/2 second");
    else
        printf("Waiting for call");

    do {
        s2 = accept(s, (struct sockaddr *) &saddr, &addrlen);

        /*
        *   Wait 1/2 second and try again 
        */

        Sleep(500);

        printf(".");
    }
    while (s2 == INVALID_SOCKET && h_errno == WSAEWOULDBLOCK);

    printf("\n");

    if (verbose)
        printf("\naccept() returned, new socket = 0x%X (%d)\n", s2, s2);

    if (s2 == INVALID_SOCKET) {
        dos_net_perror("accept call failed");
        closesocket(s);
        return 1;
    }

    /*
    *   Print out who connected to us 
    */

    if (verbose) {
        printf("addrlen = %d\n", addrlen);
        print_netaddr(saddr.sa_netnum, "Callers address = ", "\n");
    }

    *callsock = s2;

    return 0;
}

/****************************************************************************
*
*    FUNCTION:  do_recv_send( SOCKET s2 )
*
*    PURPOSE:   Waits for someone to connect.
*
*    ARGUMENTS:	SOCKET socket to transmit on
*
*	 RETURNS:   0 if ok
*				1 if error
*
*\***************************************************************************/
int do_recv_send(SOCKET s2)
{
    int rc, rcount = 0;
    int nbytes, errflag = 0;
    LPSTR recvbuf;

    if (verbose)
        printf("allocating %d bytes for receive buffer\n", Receive_Length);

    recvbuf = malloc(Receive_Length);

    if (!recvbuf) {
        printf("Error allocating %d bytes for receive buffer\n", Receive_Length);
        return 1;
    }

    /*
    *   Recv packets and send them back 
    */

    while (1) {

        /*
        *   Receive data 
        */

        if (verbose)
            printf("calling recv(socket = %d, receive length = %d)\n", s2, Receive_Length);

        nbytes = recv(s2, recvbuf, Receive_Length, 0);

        if (nbytes == SOCKET_ERROR) {
            dos_net_perror("recv call failed");
            errflag++;
            break;
        }

        if (verbose)
            printf("Received packet %d: received %d bytes\n", rcount++, nbytes);
        else
            printf("\rReceived packet %d: received %d bytes... ", rcount++, nbytes);

        /*
        *   Send the data back 
        */
	
        if (verbose)
            printf("calling send(socket = %d, send length = %d)\n", s2, nbytes);

        rc = send(s2, recvbuf, nbytes, 0);

        if (rc == SOCKET_ERROR) {
            dos_net_perror("send call failed");
            errflag++;
            break;
        }

        printf("Sent %d bytes", rc);

        if (verbose)
            printf("\n");

        if (No_Loop)
            break;
    }

    if (verbose)
        printf("freeing receive buffer\n");

    free(recvbuf);

    return errflag;
}

smwhotjay 2017-12-05
  • 打赏
  • 举报
回复
看我的网络编程书吧。 accept 阻塞接收即可。开个accept的线程专门做接受连接。 http://blog.csdn.net/smwhotjay/article/details/50451749
chen_JADE 2017-12-05
  • 打赏
  • 举报
回复
在监听类里面获取客户端的Socket对象。 参考:
void ClistenClient::OnAccept(int nErrorCode)
{
       CPaneClient* pSock = new CPaneClient;
	if(Accept(*pSock))
		theApp.m_list.AddTail(pSock);
         else
		delete pSock;
	  CSocket::OnAccept(nErrorCode);
}
oyljerry 2017-12-05
  • 打赏
  • 举报
回复
一般accept这个用阻塞的方式的,如你处理的,接收返回的socket,然后再后续接收数据的时候,可以用非阻塞。select来调度处理

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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