在网上下了utral vnc里面的repeater(repeater的作用是,在N个局域网中充当使者,进行通信),看了一下,里面实现的思路是Client与Server端配(即一个Server端的连接对应一个Client端的连接)对后开了一个线程去do_repeater,由于我用时是Server数量很少的,而Client很多,这样每开一个线程的话就会造成Server端很大的网络负担。现在我想这样,Server端在repeater里面只连接一次,而能通过repeater转发给这个Server对应的所有Client程序,我看了一下do_repeater函数,用了io模型,里面的对应关系看得我云里雾里的,希望有人能帮我一下。谢谢下面是do_repeater:(local_in,local_out都是client连接套接字,remote是Server端连接进来的套接字)
DWORD WINAPI do_repeater(LPVOID lpParam)
{
/** vars for local input data **/
char lbuf[1029]; /* local input buffer */
int lbuf_len=0; /* available data in lbuf */
int f_local; /* read local input more? */
/** vars for remote input data **/
char rbuf[1029]; /* remote input buffer */
int rbuf_len; /* available data in rbuf */
int f_remote; /* read remote input more? */
/** other variables **/
int nfds, len;
fd_set *ifds, *ofds;
struct timeval *tmo;
// struct timeval win32_tmo;
SOCKET local_in=0;
SOCKET local_out=0;
SOCKET remote=0;
ULONG code=0;
long recvbytes=0;
long sendbytes=0;
int nummer;
pmystruct inout=(pmystruct)lpParam;
local_in=inout->local_in;
local_out=inout->local_out;
remote=inout->remote;
code=inout->code;
nummer=inout->nummer;
LogStats2(code);
lbuf_len = 0;
rbuf_len = 0; if (inout->server)
{
memcpy(lbuf,Viewers[nummer].preloadbuffer,Viewers[nummer].size_buffer);
lbuf_len=Viewers[nummer].size_buffer;
Viewers[nummer].size_buffer=0;
}
else
{
memcpy(lbuf,Servers[nummer].preloadbuffer,Servers[nummer].size_buffer);
lbuf_len=Servers[nummer].size_buffer;
Servers[nummer].size_buffer=0;
} if ( 0 < lbuf_len )
{
if (inout->server) len = send(remote, lbuf, lbuf_len, 0);
else len = send(local_in, lbuf, lbuf_len, 0);
if ( 1 < f_debug ) //* more verbose
report_bytes( ">>>", lbuf, lbuf_len);
if ( len == -1 ) {
debug("send() failed, %d\n", socket_errno());
goto error;
} else if ( 0 < len ) {
//* move data on to top of buffer
sendbytes+=len;
lbuf_len -= len;
if ( 0 < lbuf_len )
memcpy( lbuf, lbuf+len, lbuf_len );
assert( 0 <= lbuf_len );
}
}
LogStats2(code);
/* repeater between stdin/out and socket */
nfds = ((local_in<remote)? remote: local_in) +1;
ifds = FD_ALLOC(nfds);
ofds = FD_ALLOC(nfds);
f_local = 1; /* yes, read from local */
f_remote = 1; /* yes, read from remote */ while ( f_local || f_remote ) {
FD_ZERO( ifds );
FD_ZERO( ofds );
tmo = NULL; /** prepare for reading local input **/
if ( f_local && (lbuf_len < sizeof(lbuf)) ) {
FD_SET( local_in, ifds );
}
/** prepare for reading remote input **/
if ( f_remote && (rbuf_len < sizeof(rbuf)) ) {
FD_SET( remote, ifds );
}
/* FD_SET( local_out, ofds ); */
/* FD_SET( remote, ofds ); */
if ( select( nfds, ifds, ofds, NULL, tmo ) == -1 ) {
/* some error */
error( "select() failed, %d\n", socket_errno());
goto error;
}
/* fake ifds if local is stdio handle because
select() of Winsock does not accept stdio
handle. */ /* remote => local */
if ( FD_ISSET(remote, ifds) && (rbuf_len < sizeof(rbuf)) ) {
len = recv( remote, rbuf + rbuf_len, sizeof(rbuf)-rbuf_len, 0);
if ( len == 0 ) {
debug("connection closed by peer\n");
goto error; } else if ( len == -1 ) {
if (socket_errno() != ECONNRESET) {
/* error */
fatal("recv() faield, %d\n", socket_errno());
goto error;
} else {
debug("ECONNRESET detected\n");
goto error;
}
} else {
recvbytes +=len;
if ( 1 < f_debug ) /* more verbose */
report_bytes( "<<<", rbuf, rbuf_len);
rbuf_len += len;
}
}
/* local => remote */
if ( FD_ISSET(local_in, ifds) && (lbuf_len < sizeof(lbuf)) ) { len = recv(local_in, lbuf + lbuf_len,sizeof(lbuf)-lbuf_len, 0); if ( len == 0 ) {
/* stdin is EOF */
debug("local input is EOF\n");
goto error;
} else if ( len == -1 ) {
/* error on reading from stdin */
goto error;
} else {
/* repeat */
lbuf_len += len;
}
}
/* flush data in buffer to socket */
if ( 0 < lbuf_len ) {
len = send(remote, lbuf, lbuf_len, 0);
if ( 1 < f_debug ) /* more verbose */
report_bytes( ">>>", lbuf, lbuf_len);
if ( len == -1 ) {
debug("send() failed, %d\n", socket_errno());
goto error;
} else if ( 0 < len ) {
/* move data on to top of buffer */
sendbytes+=len;
lbuf_len -= len;
if ( 0 < lbuf_len )
memcpy( lbuf, lbuf+len, lbuf_len );
assert( 0 <= lbuf_len );
}
}
/* flush data in buffer to local output */
if ( 0 < rbuf_len ) { len = send( local_out, rbuf, rbuf_len, 0);
if ( len == -1 ) {
debug("output (local) failed, errno=%d\n", errno);
goto error;
}
else
{
rbuf_len -= len;
if ( len < rbuf_len )
memcpy( rbuf, rbuf+len, rbuf_len );
assert( 0 <= rbuf_len );
}
} }
error:
LogStats(code,recvbytes,sendbytes);
f_remote = 0; /* no more read from socket */
f_local = 0;
closesocket(local_in);
closesocket(remote);
shutdown(local_in, 1);
shutdown(remote, 1);
local_in=0;
remote=0;
Remove_server_list(code);
Remove_viewer_list(code);
return 0;
}
DWORD WINAPI do_repeater(LPVOID lpParam)
{
/** vars for local input data **/
char lbuf[1029]; /* local input buffer */
int lbuf_len=0; /* available data in lbuf */
int f_local; /* read local input more? */
/** vars for remote input data **/
char rbuf[1029]; /* remote input buffer */
int rbuf_len; /* available data in rbuf */
int f_remote; /* read remote input more? */
/** other variables **/
int nfds, len;
fd_set *ifds, *ofds;
struct timeval *tmo;
// struct timeval win32_tmo;
SOCKET local_in=0;
SOCKET local_out=0;
SOCKET remote=0;
ULONG code=0;
long recvbytes=0;
long sendbytes=0;
int nummer;
pmystruct inout=(pmystruct)lpParam;
local_in=inout->local_in;
local_out=inout->local_out;
remote=inout->remote;
code=inout->code;
nummer=inout->nummer;
LogStats2(code);
lbuf_len = 0;
rbuf_len = 0; if (inout->server)
{
memcpy(lbuf,Viewers[nummer].preloadbuffer,Viewers[nummer].size_buffer);
lbuf_len=Viewers[nummer].size_buffer;
Viewers[nummer].size_buffer=0;
}
else
{
memcpy(lbuf,Servers[nummer].preloadbuffer,Servers[nummer].size_buffer);
lbuf_len=Servers[nummer].size_buffer;
Servers[nummer].size_buffer=0;
} if ( 0 < lbuf_len )
{
if (inout->server) len = send(remote, lbuf, lbuf_len, 0);
else len = send(local_in, lbuf, lbuf_len, 0);
if ( 1 < f_debug ) //* more verbose
report_bytes( ">>>", lbuf, lbuf_len);
if ( len == -1 ) {
debug("send() failed, %d\n", socket_errno());
goto error;
} else if ( 0 < len ) {
//* move data on to top of buffer
sendbytes+=len;
lbuf_len -= len;
if ( 0 < lbuf_len )
memcpy( lbuf, lbuf+len, lbuf_len );
assert( 0 <= lbuf_len );
}
}
LogStats2(code);
/* repeater between stdin/out and socket */
nfds = ((local_in<remote)? remote: local_in) +1;
ifds = FD_ALLOC(nfds);
ofds = FD_ALLOC(nfds);
f_local = 1; /* yes, read from local */
f_remote = 1; /* yes, read from remote */ while ( f_local || f_remote ) {
FD_ZERO( ifds );
FD_ZERO( ofds );
tmo = NULL; /** prepare for reading local input **/
if ( f_local && (lbuf_len < sizeof(lbuf)) ) {
FD_SET( local_in, ifds );
}
/** prepare for reading remote input **/
if ( f_remote && (rbuf_len < sizeof(rbuf)) ) {
FD_SET( remote, ifds );
}
/* FD_SET( local_out, ofds ); */
/* FD_SET( remote, ofds ); */
if ( select( nfds, ifds, ofds, NULL, tmo ) == -1 ) {
/* some error */
error( "select() failed, %d\n", socket_errno());
goto error;
}
/* fake ifds if local is stdio handle because
select() of Winsock does not accept stdio
handle. */ /* remote => local */
if ( FD_ISSET(remote, ifds) && (rbuf_len < sizeof(rbuf)) ) {
len = recv( remote, rbuf + rbuf_len, sizeof(rbuf)-rbuf_len, 0);
if ( len == 0 ) {
debug("connection closed by peer\n");
goto error; } else if ( len == -1 ) {
if (socket_errno() != ECONNRESET) {
/* error */
fatal("recv() faield, %d\n", socket_errno());
goto error;
} else {
debug("ECONNRESET detected\n");
goto error;
}
} else {
recvbytes +=len;
if ( 1 < f_debug ) /* more verbose */
report_bytes( "<<<", rbuf, rbuf_len);
rbuf_len += len;
}
}
/* local => remote */
if ( FD_ISSET(local_in, ifds) && (lbuf_len < sizeof(lbuf)) ) { len = recv(local_in, lbuf + lbuf_len,sizeof(lbuf)-lbuf_len, 0); if ( len == 0 ) {
/* stdin is EOF */
debug("local input is EOF\n");
goto error;
} else if ( len == -1 ) {
/* error on reading from stdin */
goto error;
} else {
/* repeat */
lbuf_len += len;
}
}
/* flush data in buffer to socket */
if ( 0 < lbuf_len ) {
len = send(remote, lbuf, lbuf_len, 0);
if ( 1 < f_debug ) /* more verbose */
report_bytes( ">>>", lbuf, lbuf_len);
if ( len == -1 ) {
debug("send() failed, %d\n", socket_errno());
goto error;
} else if ( 0 < len ) {
/* move data on to top of buffer */
sendbytes+=len;
lbuf_len -= len;
if ( 0 < lbuf_len )
memcpy( lbuf, lbuf+len, lbuf_len );
assert( 0 <= lbuf_len );
}
}
/* flush data in buffer to local output */
if ( 0 < rbuf_len ) { len = send( local_out, rbuf, rbuf_len, 0);
if ( len == -1 ) {
debug("output (local) failed, errno=%d\n", errno);
goto error;
}
else
{
rbuf_len -= len;
if ( len < rbuf_len )
memcpy( rbuf, rbuf+len, rbuf_len );
assert( 0 <= rbuf_len );
}
} }
error:
LogStats(code,recvbytes,sendbytes);
f_remote = 0; /* no more read from socket */
f_local = 0;
closesocket(local_in);
closesocket(remote);
shutdown(local_in, 1);
shutdown(remote, 1);
local_in=0;
remote=0;
Remove_server_list(code);
Remove_viewer_list(code);
return 0;
}
VNC的代码有VC版本的,那么用VC来调试跟踪。这样也许好理解一些。