【Linux網路程式設計-2】TcpServer類、TcpClient類

neon233發表於2024-06-28

把socket的一些函式封裝

//TcpClient.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <netdb.h>
class TcpClient
{
private:
    int m_sockfd;
    char m_ip[21]; 
    int m_port;
    bool m_btimeout;    //Read/Write是否是因為超時而返回false,超時為true
    int m_bufferlen;
public:
    TcpClient();
    ~TcpClient();

    bool ConnectServer(const char* ip, int port);
    
    bool Readn(const int sockfd, char* buffer, const size_t n);
    bool Writen(const int sockfd, char* buffer, const size_t n);
    bool TcpRead(int sockfd, char* buffer, int* ibuflen, const int timeout=0);
    bool TcpWrite(int sockfd, char* buffer, int* ibuflen=0);
    
    bool Read(char* buffer, const int timeout);
    bool Write(char* buffer, int ibuflen=0);

    void Close();

};

//TcpClient.cpp
#include "TcpClient.h"

TcpClient::TcpClient()
{
    m_sockfd=-1;
    memset(m_ip, 0, sizeof(m_ip));
    m_port=0;
    m_btimeout=false;
    m_bufferlen=0;
}

TcpClient::~TcpClient()
{
    Close();
}


bool TcpClient::ConnectServer(const char* ip, int port)
{
    if(m_sockfd != -1)
    {
        Close();
    }

    //memcpy(m_ip, ip, sizeof(ip));
    strcpy(m_ip,ip);
    m_port=port;

    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family=AF_INET;

    /*
	struct hostent* host;
	if(!(host = gethostbyname(m_ip)))	//dns解析
	{
	    Close();
    	return false;
	}
	
	memcpy(&server_addr.sin_addr, &host->h_addr, host->h_length);	
	*/
	server_addr.sin_addr.s_addr=inet_addr(m_ip);	
	server_addr.sin_port=htons(m_port);
	
    m_sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(m_sockfd==-1)
    {
        return false;
    }

 
	if(connect(m_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        Close();
        return false;
    }

    return true;
}

bool TcpClient::Readn(const int sockfd, char* buffer, const size_t n)
{
        if(sockfd==-1 || NULL==buffer) return false;
        int nleft,nread,idx;
        nleft=n;
        nread=0;
        idx=0;
        while(nleft>0)
        {
            if((nread = recv(sockfd, buffer+idx, nleft, 0))<=0)
	        {
		        fprintf(stderr, "Error: %s\n", strerror(errno));
	            return false;
	        }
	        nleft-=nread;
    	    idx+=nread;
        }
        return true;
}

 bool TcpClient::Writen(const int sockfd, char* buffer, const size_t n)
{
        if(sockfd==-1 || NULL==buffer) return false;
        int nleft,nwrite,idx;
        nleft=n;
        nwrite=0;
        idx=0;

    while(nleft>0)
    {
        if((nwrite = send(sockfd, buffer+idx, nleft, 0))<=0)
	   {
		    fprintf(stderr, "Error: %s\n", strerror(errno));
	        return false;
	    }
	        nleft-=nwrite;
    	    idx+=nwrite;
    }
    return true;
}


bool TcpClient::TcpRead(int sockfd, char* buffer, int* ibuflen, const int timeout)
{
        if(sockfd==-1 || NULL==buffer || NULL==ibuflen)	return false;
       
        fd_set tmpfd;
        
        FD_ZERO(&tmpfd);
        FD_SET(sockfd,&tmpfd);
        
        struct timeval ttimeout;
        ttimeout.tv_sec=timeout;
        ttimeout.tv_usec=0;
        
        int i;
        if((i=select(sockfd+1,0,&tmpfd,0,&ttimeout))<=0)	return false;
        (*ibuflen)=0;
        if(Readn(sockfd,(char*)ibuflen,4)==false)	return false;	//讀取資料長度到ibuflen
        (*ibuflen)=ntohl(*ibuflen);	//ibuflen轉主機序
        
        if(Readn(sockfd, buffer, (*ibuflen))==false)	return false;
        return true;
}

 bool TcpClient::TcpWrite(int sockfd, char* buffer, int* ibuflen)
 {
        if(sockfd==-1 || NULL==buffer || NULL==ibuflen)	return false;
        
	fd_set tmpfd;
        
        FD_ZERO(&tmpfd);
        FD_SET(sockfd,&tmpfd);
        
        struct timeval timeout;
        timeout.tv_sec=5;
        timeout.tv_usec=0;
        
        if(select(sockfd+1,0,&tmpfd,0,&timeout)<=0)	return false;
        int ilen=1;
        if(ibuflen==0)	ilen=strlen(buffer);    //ibuflen==0設為寫入的是字串
        else ilen=*ibuflen;	//ibuflen!=0設為寫入二進位制資料
        
        int ilenn=htonl(ilen);	
       
       	char strBufferTmp[ilen+4];	//儲存長度+資料資料包

        memset(strBufferTmp,0,ilen+4);
        memcpy(strBufferTmp,&ilenn,4);	//存長度
        memcpy(strBufferTmp+4,buffer,ilen);	//存資料
	
        if(Writen(sockfd, strBufferTmp, ilen+4) == false)	return false;
        return true;
}


bool TcpClient::Read(char* buffer, const int timeout)
{
    if(m_sockfd==-1)	return false;	   
    if(timeout>0)
    {
        fd_set tmpfd;
    
    	FD_ZERO(&tmpfd);
    	FD_SET(m_sockfd,&tmpfd);
    
    	struct timeval _timeout;
    	_timeout.tv_sec=timeout;
    	_timeout.tv_usec=0;
        m_btimeout=false;

        int i; 
        if((i=select(m_sockfd+1,0,&tmpfd,0,&_timeout))<=0)	
    	{
        	if(i==0)
            	m_btimeout=true;
        	return false;
    	}
    }
    m_bufferlen=0;
    return TcpRead(m_sockfd, buffer, &m_bufferlen); 
}


bool TcpClient::Write(char* buffer, int ibuflen)
{
    if(m_sockfd==-1)	return false;
    
    fd_set tmpfd;
    
    FD_ZERO(&tmpfd);
    FD_SET(m_sockfd,&tmpfd);
    
    struct timeval timeout;
    timeout.tv_sec=5;
    timeout.tv_usec=0;
    
    int i;
    if((i=select(m_sockfd+1,0,&tmpfd,0,&timeout))<=0)	
    {
        if(i==0)
            m_btimeout=true;
        return false;
    }
    int ilen=ibuflen;
    if(ilen==0)
        ilen=strlen(buffer);
    
    return TcpWrite(m_sockfd, buffer, &ilen);
}

void TcpClient::Close()
{
    close(m_sockfd);
    m_sockfd=-1;
}

//TcpServer.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <errno.h>

class TcpServer
{
private:
    struct sockaddr_in m_server_addr;
    struct sockaddr_in m_client_addr;
    int m_client_addr_size;
public:
    int m_listenBacklog=100;
    unsigned int m_port;   
    int m_listenfd;
    int m_clientfd;
    bool m_btimeout;
    int m_bufferlen;
public:
    TcpServer();
    ~TcpServer();
    bool InitServer(const unsigned int port);
    bool Accept();


    bool Readn(const int sockfd, char* buffer, const size_t n);
    bool Writen(const int sockfd, char* buffer, const size_t n);
    bool TcpRead(int sockfd, char* buffer, int* ibuflen, const int timeout=0);
    bool TcpWrite(int sockfd, char* buffer, int* ibuflen=0);

    bool Read(char* buffer, const int timeout=0);
    bool Write(char* buffer, int ibuflen=0);
    char* GetIP();
    void CloseListen(); 
    void CloseClient();

};

//TcpServer.cpp
#include "TcpServer.h"


TcpServer::TcpServer()
{
    m_port=-1;
    m_listenfd=-1;
    m_client_addr_size=0;
    m_bufferlen=0;
    m_btimeout=false;	//Read/Write是否是因為超時而返回false,超時為true
}

TcpServer::~TcpServer()
{
    CloseListen();
    CloseClient();
}

bool TcpServer::InitServer(const unsigned int port)
{
    if(m_listenfd>0)
    {
        close(m_listenfd);
        m_listenfd=-1;
    }
	
    m_listenfd = socket(PF_INET, SOCK_STREAM, 0);
    
    if(m_listenfd == -1) return false;


    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
	
    memset(&m_server_addr, 0, sizeof(m_server_addr));
    m_server_addr.sin_family=AF_INET;
    m_server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    m_server_addr.sin_port=htons(port);

    if(bind(m_listenfd, (struct sockaddr*) &m_server_addr, sizeof(m_server_addr)) == -1)
    {
        CloseListen();
        return false;
    }
    
    if(listen(m_listenfd, m_listenBacklog) == -1)
    {
        CloseListen();
        return false;
    }

    m_client_addr_size=sizeof(m_client_addr);
    return true;
}

bool TcpServer::Accept()
{
    if(m_listenfd == -1)    return false;
    if((m_clientfd = accept(m_listenfd, (struct sockaddr*)&m_client_addr,(socklen_t*)&m_client_addr_size)) == -1)	return false;
    return true;
}


bool  TcpServer::Readn(const int sockfd, char* buffer, const size_t n)
{
        if(sockfd==-1 || NULL==buffer) return false;
        int nleft,nread,idx;
        nleft=n;
        nread=0;
        idx=0;
        while(nleft>0)
        {
            if((nread = recv(sockfd, buffer+idx, nleft, 0))<=0)
	        {
		        fprintf(stderr, "Error: %s\n", strerror(errno));
	            return false;
	        }
	        nleft-=nread;
    	    idx+=nread;
        }
        return true;
}

 bool  TcpServer::Writen(const int sockfd, char* buffer, const size_t n)
{
        if(sockfd==-1 || NULL==buffer) return false;
        int nleft,nwrite,idx;
        nleft=n;
        nwrite=0;
        idx=0;
        while(nleft>0)
        {
            if((nwrite = send(sockfd, buffer+idx, nleft, 0))<=0)
	        {
		        fprintf(stderr, "Error: %s\n", strerror(errno));
	            return false;
	        }
	        nleft-=nwrite;
    	    idx+=nwrite;
        }
        return true;
}


bool TcpServer::TcpRead(int sockfd, char* buffer, int* ibuflen, const int timeout)
{
        if(sockfd==-1 || NULL==buffer || NULL==ibuflen)	return false;
       
        fd_set tmpfd;
        
        FD_ZERO(&tmpfd);
        FD_SET(sockfd,&tmpfd);
        
        struct timeval ttimeout;
        ttimeout.tv_sec=timeout;
        ttimeout.tv_usec=0;
        
        int i;
        if((i=select(sockfd+1,0,&tmpfd,0,&ttimeout))<=0)	return false;
        (*ibuflen)=0;
        if(Readn(sockfd,(char*)ibuflen,4)==false)	return false;	
        (*ibuflen)=ntohl(*ibuflen);	
        
        if(Readn(sockfd, buffer, (*ibuflen))==false)	return false;
        return true;
}

 bool TcpServer::TcpWrite(int sockfd, char* buffer, int* ibuflen)
 {
        if(sockfd==-1 || NULL==buffer || NULL==ibuflen)	return false;
        
		fd_set tmpfd;
        
        FD_ZERO(&tmpfd);
        FD_SET(sockfd,&tmpfd);
        
        struct timeval timeout;
        timeout.tv_sec=5;
        timeout.tv_usec=0;
        
        if(select(sockfd+1,0,&tmpfd,0,&timeout)<=0)	return false;
        int ilen=1;
        if(ibuflen==0)	ilen=strlen(buffer);    
        else ilen=*ibuflen;	
        
        int ilenn=htonl(ilen);	
       
       	char strBufferTmp[ilen+4];	
        memset(strBufferTmp,0,ilen+4);
        memcpy(strBufferTmp,&ilenn,4);	
        memcpy(strBufferTmp+4,buffer,ilen);	
        
        if(Writen(sockfd, strBufferTmp, ilen+4) == false)	return false;
        return true;
}

bool TcpServer::Read(char* buffer, const int timeout)
{
    if(m_clientfd==-1)	return false;	   
    if(timeout>0)
    {
        fd_set tmpfd;
    
    	FD_ZERO(&tmpfd);
    	FD_SET(m_clientfd,&tmpfd);
    
    	struct timeval _timeout;
    	_timeout.tv_sec=timeout;
    	_timeout.tv_usec=0;
        m_btimeout=false;

        int i; 
        if((i=select(m_clientfd+1,0,&tmpfd,0,&_timeout))<=0)	
    	{
        	if(i==0)
            	m_btimeout=true;
        	return false;
    	}
    }
    m_bufferlen=0;
    return TcpRead(m_clientfd, buffer, &m_bufferlen);
}


bool TcpServer::Write(char* buffer, int ibuflen)
{
    if(m_clientfd==-1)	return false;
    
    fd_set tmpfd;
    
    FD_ZERO(&tmpfd);
    FD_SET(m_clientfd,&tmpfd);
    
    struct timeval timeout;
    timeout.tv_sec=5;
    timeout.tv_usec=0;
    
    int i;
    if((i=select(m_clientfd+1,0,&tmpfd,0,&timeout))<=0)	
    {
        if(i==0)
            m_btimeout=true;
        return false;
    }
    int ilen=ibuflen;
    if(ilen==0)
        ilen=strlen(buffer);
    
    return TcpWrite(m_clientfd, buffer, &ilen);
}
    
char* TcpServer::GetIP()
{
    return inet_ntoa(m_client_addr.sin_addr);
}
    
void TcpServer::CloseListen()
{
    close(m_listenfd);
    m_listenfd=-1;
}

void TcpServer::CloseClient()
{
    close(m_clientfd);
    m_clientfd=-1;
}

相關文章