BIO_s_connect can be used as an client socket object, and has its private data struct BIO_CONNECT, which is stored in BIO.ptr.
In the struct, a status value int BIO_CONNECT.state is introduced to record the current state of socket, and indicate what to do next step. All the states are:
#define BIO_CONN_S_BEFORE 1
#define BIO_CONN_S_GET_IP 2
#define BIO_CONN_S_GET_PORT 3
#define BIO_CONN_S_CREATE_SOCKET 4
#define BIO_CONN_S_CONNECT 5
#define BIO_CONN_S_OK 6
#define BIO_CONN_S_BLOCKED_CONNECT 7
#define BIO_CONN_S_NBIO 8
An internal function conn_state() is used to perform the appropriate operation In a dead loop till reach the status 6(BIO_CONN_S_OK).
By the way, there is one thing to be noted, the C language don't have the feature to show if a member function is a internal or public; while in the C++ language, you may use public to indicate that the function is used for class object and protect to indicate for the derived class.
Use steps:
1, create a socket bio and input host IP and port.
You may use just one line:
cbio = BIO_new_connect("localhost:2000");
the host IP and port is in one string separated by ‘:’.
Or you may initial the client BIO step by step:
unsigned long ladd = inet_addr("127.0.0.1");
cbio = BIO_new(BIO_s_connect());
iRet = BIO_set_conn_ip(cbio, &ladd);
iRet = BIO_set_conn_port(cbio, "2000");
2, then do connection:
if(BIO_do_connect(cbio) <= 0)
// do something..
About the BIO_do_connect (), here is the definition:
#define BIO_do_connect(b) BIO_do_handshake(b)
#define BIO_do_accept(b) BIO_do_handshake(b)
#define BIO_do_handshake(b) BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL)
In BIO_C_DO_STATE_MACHINE conn_state()is called, in which a dead loop is used to update state, until BIO_CONN_S_OK is reached or error happens.
3, send and receive data
Then you may use the two function to send data,
int BIO_puts(BIO *b, const char *in); // for string
int BIO_write(BIO *b, const void *in, int inl); // for raw data
and int BIO_read(BIO *b, void *out, int outl) to receive data.
If the remote peer closed, the BIO_read() will wake and return 0, return -1 if error happens;
Here is a complete client peer sample:
#include "stdafx.h" #include <WinSock2.h> #include <openssl/bio.h> #include <openssl/err.h>
int _tmain(int argc, _TCHAR* argv[]) { BIO *cbio, *out; int len; char tmpbufin[1024] = {0}; char tmpbufout[1024] = {0}; ERR_load_crypto_strings();
cbio = BIO_new_connect("localhost:2000");
// another way to initial client BIO //unsigned long ladd = inet_addr("127.0.0.1"); //cbio = BIO_new(BIO_s_connect()); //if (NULL == cbio) return 0; //iRet = BIO_set_conn_ip(cbio, &ladd); //iRet = BIO_set_conn_port(cbio, "2000");
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if(BIO_do_connect(cbio) <= 0) { ERR_print_errors_fp(stderr); return 0; /* whatever ... */ } printf("have connected to server/ninput data and press enter to send/n");
for(;;) {
memset(tmpbufout,0,sizeof(tmpbufout)); memset(tmpbufin,0,sizeof(tmpbufin));
scanf("%s", tmpbufout); if (0 == strcmp(tmpbufout, "quit")) break; if ((len = strlen(tmpbufout)) <= 0) break; len = BIO_write(cbio, tmpbufout, len + 1); if (len <= 0) break;
len = BIO_read(cbio, tmpbufin, 1024); if(len <= 0) break; sprintf(tmpbufout, "from Server:%s/n", tmpbufin); BIO_write(out, tmpbufout, strlen(tmpbufout)); } BIO_free(cbio); BIO_free(out); } |