⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.cpp

📁 自动调整大小的进程池类的实现。 一个运用进程池的server类。 一个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 + -