Server socket BIO (BIO_s_accept)

本文详细介绍了BIO_s_accept的功能及使用方法,包括如何创建服务器监听生物对象、接受客户端连接并获取远程客户端IP地址等内容。此外,还提供了一个完整的回显服务器示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BIO_s_accept can be used as an server socket object, and has it’s own data struct BIO_ACCEPT, which is stored in BIO.ptr. in the struct, a status value BIO_ACCEPT.state is introduced to record the current state of socket, The statues are:

#define ACPT_S_BEFORE               1

#define ACPT_S_GET_ACCEPT_SOCKET   2

#define ACPT_S_OK               3

The status indicate what to do next step. Use the internal function conn_state() take the next action. Until call the blocking accept() or an error happens.

The BIO_s_connect’s bio_accept_st uses a bio list to restores the accepted socket, and add the remote socket at the end of the list.

If the remote client is closed, the BIO_read() will wake and return 0; if the close is not graceful, will return -1;

 

Notes that all the socket functions run in blocking mode.

All the functions are implemented in file Bss_acpt.c.

 

Use steps:

    Create a socket bio and input port number.

    You may use just one line:

BIO *abio = BIO_new_accept("2000");

Then accept:

    If (BIO_do_accept(abio) <= 0) …

Notes the function only initial the BIO, if wanna accept connection you need to call it twice. The first time push state from ACPT_S_BEFORE  to ACPT_S_GET_ACCEPT_SOCKET, the second time do the actual accept BIO_accept().

 

Get remote IP

So strange, BIO_s_accept doesn’t support get the remove IP. Only can get the port number… while the BIO popped don’t have a BIO.ptr, and can only be used to send and recv data.

/* BIO_s_accept_socket() */

#define BIO_set_accept_port(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name)

#define BIO_get_accept_port(b)  BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0)

/* #define BIO_set_nbio(b,n)    BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */

#define BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(n)?"a":NULL)

#define BIO_set_accept_bios(b,bio) BIO_ctrl(b,BIO_C_SET_ACCEPT,2,(char *)bio)

Our solution: to get remote IP:

       char* pch = NULL;

       pch = ((BIO_ACCEPT*)(abio->ptr))->addr;

and you have to copy definition of BIO_ACCEPT ahead of code, and BIO_ACCEPT.addr only restore the recent connected client IP.

 

And also you may get the remote IP by the classical way:

       SOCKET sClient = (SOCKET)BIO_get_fd(cbio, NULL);

       SOCKADDR sName;

       int iAddLen = sizeof(sName);

       getpeername(sClient, &sName, &iAddLen);

 

OK, said so much, now give the sample echo server code:

 

DWORD WINAPI listenThread(LPVOID lpParameter)

{

    BIO *abio, *cbio;

    HANDLE hThread;

    unsigned long ulthID = 0;

 

    if (NULL == (abio = BIO_new_accept("2000")))

       return 0;

 

    if(BIO_do_accept(abio) <= 0) {

       printf("Error setting up accept/n");

       return 0;

    }

    printf("Server started/n");

 

    while(TRUE) {

 

       if(BIO_do_accept(abio) <= 0) {

           printf("Error setting up accept/n");

           return 0;

       }

 

       // try to get client IP

       char* pch = NULL;

       pch = ((BIO_ACCEPT*)(abio->ptr))->addr;

       //pch = BIO_get_accept_port(abio);

       printf("client IP:%s/n", pch);

 

       cbio = BIO_pop(abio);

       //SOCKET sClient = (SOCKET)BIO_get_fd(cbio, NULL);

       //SOCKADDR sName;

       //int iAddLen = sizeof(sName);

       //getpeername(sClient, &sName, &iAddLen);

       //pch = inet_ntoa(*(in_addr*)(sName.sa_data +2));

       //printf("client IP:%s/n", pch);

 

       hThread = CreateThread(NULL, 0, rwThread, cbio, NULL, &ulthID);

       if (hThread == NULL) {

           printf("CreateThread failed./n" );

           return 0;

       }

       printf("client thread %x created/n", ulthID);

    }

}

 

DWORD WINAPI listenThreadBss(LPVOID lpParameter)

{

    BIO *bClient=NULL,*bAccept=NULL;

    int sock,ret;

    char *addr=NULL;

    HANDLE hThread;

    unsigned long ulthID = 0;

   

    if (INVALID_SOCKET == (sock = BIO_get_accept_socket("2000", BIO_BIND_NORMAL)))

       return 0;

    printf("Server started/n");

   

    while(TRUE) {

 

       // the same as accept, blocking mode, with the address containing remote client address.

       // but if addr == NULL, memory would be allocated.

       // the ret is the SOCKET object.

       if (INVALID_SOCKET == (ret = BIO_accept(sock,&addr)))

           return 0;

       printf("client IP:%s/n", addr);

 

       bClient = BIO_new(BIO_s_socket());

       if (NULL == bClient)

           return 0;

       // set the SOCKET object "ret" into bio.num. then the bClient can be used to read and write from remote client.

       BIO_set_fd(bClient,ret,BIO_NOCLOSE);

 

       hThread = CreateThread(NULL, 0, rwThread, bClient, NULL, &ulthID);

       if (hThread == NULL) {

           printf("CreateThread failed./n" );

       }

       printf("client thread %x created/n", ulthID);

    }  

}

 

DWORD WINAPI rwThread(LPVOID lpParameter)

{

    BIO *cbio = (BIO *)lpParameter;

    int        sock,ret,len;

    char          *addr=NULL;

    char          in[80];

    unsigned long ulthID = GetCurrentThreadId();

 

    while(1)

    {

       memset(in,0,80);

       len=BIO_read(cbio,in,80);

       if(in[0]=='q' || -1 == len)

           break;

       printf("thread %x from the client: %s/n",ulthID, in);

 

       // echo the message

       len = BIO_write(cbio, in, len);

       if (0 == len)

           break;

    }

    BIO_free(cbio);

    return 0;

}

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    HANDLE hThread;

 

    hThread = CreateThread(NULL, 0, listenThread, NULL, NULL, NULL);

    //hThread = CreateThread(NULL, 0, listenThreadBss, NULL, NULL, NULL);

    if (hThread == NULL) {

       printf("CreateThread failed./n" );

    }

 

    WaitForSingleObject(hThread, INFINITE);

 

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值