?? socket.cpp
字號:
/**
* Copyright 2007,神州數碼(中國)有限公司
* All rights reserved.
*
* 文件名稱:socket
* 摘 要:socket
*
* 當前版本:
* 作 者:
* 完成日期:
*
* 取代版本:1.1
* 原 作 者:gaozh
* 完成日期:2007年
*
*
*/
#include "socket.h"
extern volatile sig_atomic_t QuitFlag;
void ignore_pipe()
{
struct sigaction sig;
sig.sa_handler = SIG_IGN;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
sigaction(SIGPIPE,&sig,NULL);
}
/**
* 以const char類型的端口為參數的ServerSocket的構造函數。
* 首先設置監聽端口號,然后初始化tcp類型的socket
*/
ServerSocket::ServerSocket( const char* ps_port )
{
ignore_pipe( );
set_port( ps_port );
init_socket( SOCK_STREAM );
}
/**
* 以const int類型的端口為參數的ServerSocket的構造函數。
* 首先設置監聽端口號,然后初始化tcp類型的socket
*/
ServerSocket::ServerSocket( const int& port )
{
ignore_pipe( );
set_port( port );
init_socket( SOCK_STREAM );
}
ServerSocket::ServerSocket( const string& port )
{
ignore_pipe( );
set_port( port.c_str( ) );
init_socket( SOCK_STREAM );
}
/**
* 設置監聽端口號
*/
bool ServerSocket::set_port( const char *ps_port )
{
long int port;
char *errpos;
port = strtol( ps_port, &errpos, 0 );
if ( ( errpos[0] != 0 ) || ( port < 1 ) || ( port > 65535 ) )
/* Invalid port address */
return false;
/* convert to network byte order */
_port = htons(port);
return true;
}
/**
* 設置監聽端口號
*/
bool ServerSocket::set_port( const int& port )
{
long int l_port;
char *errpos;
char ps_port[10];
memset( ps_port, 0, sizeof( ps_port ) );
sprintf( ps_port, "%d", port );
/* Not client_addr_in services, maybe a number? */
l_port = strtol( ps_port, &errpos, 0 );
if ( ( errpos[0] != 0 ) || ( port < 1 ) || ( port > 65535 ) )
/* Invalid port address */
return false;
/* convert to network byte order */
_port = htons(l_port);
return true;
}
/**
* 初始化socket
*/
bool ServerSocket::init_socket( const int& socket_type )
{
struct sockaddr_in address;
/* int reuse_addr=0, keep_alive=1; */
int reuse_addr = 1, keep_alive = 1 ;
/* step1: create a socket */
_listening_socket = socket( AF_INET, socket_type, 0 );
if ( _listening_socket < 0 )
{
perror("socket");
exit(EXIT_FAILURE);
}
/***************************************************************************/
/* set socket options */
/* Level: SOL_SOCKET */
/* Name: SO_REUSEADDR */
/* Value: 1 on; 0 off */
/* which can prevent multi-running of tcpserver. */
/* Name: SO_KEEPALIVE */
/* Value: 1 on; 0 off */
/***************************************************************************/
setsockopt( _listening_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
setsockopt( _listening_socket, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive));
/* Step2: bind() transfer address(client) with socket */
/* Setup internet address information. */
memset( &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = _port;
/*
By default, not indicate local address, it is the same as any invalid address
so, for client, who known my tcpserver address, it just can communcati0on to me.
for example, for client, 202.127.197.1,202.127.196.1 is the same .
*/
address.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind( _listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0)
{
perror("bind");
close(_listening_socket);
exit(EXIT_FAILURE);
}
/* Step3: set the socket into listen status */
if (socket_type == SOCK_STREAM) {
/* before accept(),max wait queue length */
listen( _listening_socket, 50 ); /* Queue up to five connections before
having them automatically rejected. */
} /* end if(socket_type == SOCK_STREAM) */
return true;
}
/**
* 接受連接請求
*/
Socket* ServerSocket::accept_connect( )
{
int accept_socket = -1;
struct sockaddr_in client_addr;
// socklen_t size;
int size;
struct in_addr client_addr_in;
Socket *s;
int status;
cout<<"accept"<<endl;
while( !QuitFlag )
{
/* Step4: wait for connection */
size = sizeof(struct sockaddr_in);
memset( &client_addr_in, 0, sizeof( in_addr ) );
accept_socket = accept( _listening_socket, (struct sockaddr *)&client_addr, (socklen_t *)&size );
if ( accept_socket < 0 )
{
/* Either a real error occured, or blocking was interrupted for
some reason. Only abort execution if a real error occured. */
if ( errno != EINTR )
{ /* EINTR is 'interruped system call' error */
perror("accept");
close( _listening_socket );
status = -1;
exit( status );
}
else
continue;
/* don't fork - do the accept again */
} /* end if(accept_socket<0) */
/* printf which host connect to me */
memcpy( &client_addr_in.s_addr, &client_addr.sin_addr, size );
_ipaddr = inet_ntoa( client_addr_in );
printf("gather link _ipaddr=[%s]\n",_ipaddr.c_str());
s = new Socket( accept_socket );
return s;
}
return NULL;
}
/**
* 從socket中接收數據
*/
int Socket::receive( void* in, size_t count,int timeout )
{
int flags=0;
flags=MSG_DONTWAIT;
if( timeout>0 )
{
if( !LimitTimeOut(timeout) )
return -1;
}
int nRecv=recv( _s,in,count,flags);
if( nRecv<=0 )
return -1;
return nRecv;
}
int Socket::exactrecv( void* in, size_t count,int timeout )
{
int flags=0;
flags=MSG_DONTWAIT;
if( timeout>0 )
{
if( !LimitTimeOut(timeout) )
return -1;
}
int increase=0,tmpCount=count;
for(;increase<count;)
{
int nRecv=recv( _s,(char *)in+increase,tmpCount,flags);
if( nRecv<=0 )
return -1;
increase+=nRecv;
tmpCount-=nRecv;
}
return increase;
}
bool Socket::LimitTimeOut( int time )
{
struct timeval tival;
struct timeval *pTival=NULL;
fd_set readfds;
int maxfds = 0;
tival.tv_sec = time;
tival.tv_usec = 0;
if(time>=0)
pTival=&tival;
FD_ZERO(&readfds);
FD_SET( _s, &readfds);
maxfds=(( _s > maxfds)?_s:maxfds );
if( select(maxfds + 1, &readfds, NULL, NULL, pTival) <= 0)
return false;
if(!(FD_ISSET(_s, &readfds)))
return false;
return true;
}
/**
* 向socket發送數據
*/
int Socket::Send( void *out, size_t count )
{
int this_write;
int flags= MSG_DONTWAIT;
this_write = send( _s, out, count, flags);
if(this_write<=0)
{
perror("---send-----write error!");
}
return this_write;
};
void Socket::close2( )
{
close( _s );
};
/**
* 以字符串常量為參數的ClientSocket構造函數
*/
ClientSocket::ClientSocket( const char* ipaddr, const char* port, const char* proto )
{
memset( _ipaddr, 0, sizeof( _ipaddr ) );
strcpy( _ipaddr, ipaddr );
memset( _proto, 0, sizeof( _proto ) );
strcpy( _proto, proto );
memset( _port, 0, sizeof( _port ) );
strcpy( _port, port );
ignore_pipe( );
};
/**
* 以char* 類型變量為參數的構造函數
*/
ClientSocket::ClientSocket( char* ipaddr, char* port, char* proto )
{
memset( _ipaddr, 0, sizeof( _ipaddr ) );
strcpy( _ipaddr, ipaddr );
memset( _proto, 0, sizeof( _proto ) );
strcpy( _proto, proto );
memset( _port, 0, sizeof( _port ) );
strcpy( _port, port );
ignore_pipe( );
};
/**
* 以string 類型變量為參數的構造函數
*/
ClientSocket::ClientSocket( string& ipaddr, string& port, string& proto )
{
memset( _ipaddr, 0, sizeof( _ipaddr ) );
strcpy( _ipaddr, ipaddr.c_str( ) );
memset( _proto, 0, sizeof( _proto ) );
strcpy( _proto, proto.c_str( ) );
memset( _port, 0, sizeof( _port ) );
strcpy( _port, port.c_str( ) );
ignore_pipe( );
};
/**
* ipaddr和proto是char* 類型,端口是int類型的構造函數
*/
ClientSocket::ClientSocket( char* ipaddr, int& port, char* proto )
{
memset( _ipaddr, 0, sizeof( _ipaddr ) );
strcpy( _ipaddr, ipaddr );
memset( _proto, 0, sizeof( _proto ) );
strcpy( _proto, proto );
memset( _port, 0, sizeof( _port ) );
sprintf( _port, "%d", port );
printf("_ipaddr=[%s],_proto=[%s],_port=[%s]\n",_ipaddr,_proto,_port);
ignore_pipe( );
};
/**
* ipaddr和proto是string類型,端口是int類型的構造函數
*/
ClientSocket::ClientSocket( string& ipaddr, int& port, string& proto )
{
memset( _ipaddr, 0, sizeof( _ipaddr ) );
strcpy( _ipaddr, ipaddr.c_str( ) );
memset( _proto, 0, sizeof( _proto ) );
strcpy( _proto, proto.c_str( ) );
memset( _port, 0, sizeof( _port ) );
sprintf( _port, "%d", port );
ignore_pipe( );
}
// This is a generic function to make a connection to a given server/port.
// service is the port name/number,
// type is either SOCK_STREAM or SOCK_DGRAM, and
// netaddress is the host name to connect to.
// The function returns the socket, ready for action.
Socket* ClientSocket::make_connect( )
{
Socket *s;
int port = -1;
struct in_addr *addr;
int sock, connected;
struct sockaddr_in address;
/* First convert service from a string, to a number... */
port = atoport( );
if (port == -1) {
fprintf(stderr,"make_connection: Invalid socket number.\n");
return NULL;
}
/* Next convert address from ascii text to in_addr struct */
addr = atoaddr( );
if (addr == NULL) {
fprintf(stderr,"make_connection: Invalid network address.\n");
return NULL;
}
/* Step1: create a socket */
if( strcmp( _proto, "tcp" ) == 0 ) sock = socket(AF_INET, SOCK_STREAM, 0);
else sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1) {
fprintf(stderr,"make_connection: Create socket error.\n");
return NULL;
}
// printf("Connecting to %s on port %d.\n",inet_ntoa(*addr),htons(port));
/* Step2: bind to an arbitrary return address */
/* Here bind is not required in TCP mode */
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = (port);
address.sin_addr.s_addr = addr->s_addr;
if (strcmp( _proto, "tcp" ) == 0) {
/* Step3: connect to server */
connected = connect(sock, (struct sockaddr *) &address, sizeof(address));
if (connected < 0) {
perror("connect");
return NULL;
}
s = new Socket( sock );
return s;
}
/* Otherwise, must be for udp, so bind to address. */
/* Here connect is not required in this UPD mode */
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
perror("bind");
return NULL;
}
s = new Socket( sock );
return s;
};
// Take a service name, and a service type, and return a port number. If the
// service name is not found, it tries it as a decimal number. The number
// returned is byte ordered for the network.
//
int ClientSocket::atoport( )
{
int port;
long int lport;
char *errpos;
lport = strtol(_port,&errpos,0);
if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
return -1; /* Invalid port address */
port = htons(lport);
return port;
};
// Converts ascii text to in_addr struct. NULL is returned if the address
// can not be found.
//
//
struct in_addr* ClientSocket::atoaddr( )
{
struct hostent *host;
static struct in_addr saddr;
/* First try it as aaa.bbb.ccc.ddd. */
if( ( saddr.s_addr = inet_addr(_ipaddr)) != -1 )
return &saddr;
host = gethostbyname(_ipaddr);
if (host != NULL) return (struct in_addr *) *host->h_addr_list;
return NULL;
};
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -