参考网上的实现方式,先实现一个初始的SOCKET类及客户端,服务器的继承类,后续打算实现C++ epoll的框架。现在把文件贴在下面
基类Socket.h, Socket.cpp
#ifndef _E_SOCKET_H_
#define _E_SOCKET_H_
#include <iostream>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <poll.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include "basetype.h"
using namespace std;
const unsigned int BUFF_SIZE_1024 = 1024;
const unsigned int BUFF_SIZE_2048 = 2048;
/*
typedef union tagSOCK_ADDR
{
struct sockaddr_in m_addr;
struct addrinfo hints;
}SOCK_ADDR_U;
*/
class Socket
{
public:
Socket();
virtual ~Socket();
BOOL CreateSocket();
BOOL BindSocket(const UINT uiPort);
BOOL ListenSocket()const;
BOOL AcceptSocket(Socket & in_skt)const;
BOOL ConnectSocket(std::string host, const UINT uiPort);
VOID CloseSocket();
INT SetSocketNoblocking(BOOL no);
INT Send(const std::string &str)const;
INT Recv(std::string &str)const;
BOOL Is_Valid()const
{
return sockfd != -1;
}
private:
int sockfd;
struct sockaddr_in sock_addr;
};
#endif
#include "e_socket.h"
/**************************************************************************
* |
* Function Name : Socket.Socket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
Socket::Socket()
{
memset(&sock_addr, 0, sizeof(sock_addr));
}
/**************************************************************************
* |
* Function Name : Socket.~Socket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
Socket::~Socket()
{
if (!Is_Valid())
{
CloseSocket();
}
}
/**************************************************************************
* |
* Function Name : Socket.CreateSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
BOOL Socket:: CreateSocket()
{
INT iRet = 0;
INT sockoptval = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (!Is_Valid())
{
return false;
}
/* set reuse addr */
iRet = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(sockoptval));
if (-1 == iRet)
{
return false;
}
return true;
}
/**************************************************************************
* |
* Function Name : Socket.BindSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
BOOL Socket::BindSocket(const UINT uiPort)
{
INT iRet = 0;
if (!Is_Valid())
{
return false;
}
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = INADDR_ANY;
sock_addr.sin_port = htons ( uiPort );
//inet_pton(AF_INET, pHost, &(sock_addr.sin_addr);
cout<<"server bind socket ..."<<endl;
iRet = bind(sockfd, (struct sockaddr *)&sock_addr, (socklen_t) sizeof(sock_addr));
if (-1 == iRet)
{
return false;
}
return true;
}
/**************************************************************************
* |
* Function Name : Socket.ListenSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
BOOL Socket::ListenSocket()const
{
INT iRet = 0;
if (!Is_Valid())
{
return false;
}
cout<<"listening ..."<<endl;
iRet = listen(sockfd, 10);
if (-1 == iRet)
{
return false;
}
return true;
}
/**************************************************************************
* |
* Function Name : Socket.AcceptSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
BOOL Socket::AcceptSocket(Socket & in_skt)const
{
INT addr_len = sizeof(sock_addr);
in_skt.sockfd = accept(this->sockfd, (struct sockaddr *)&this->sock_addr,
(socklen_t *)&addr_len);
if (!in_skt.Is_Valid())
{
return false;
}
return true;
}
/**************************************************************************
* |
* Function Name : Socket.ConnectSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
BOOL Socket::ConnectSocket(std::string host, const UINT uiPort)
{
INT iRet = 0;
if (!Is_Valid())
{
return false;
}
sock_addr.sin_family = AF_INET;
//sock_addr.sin_port = htonl(uiPort);
/*
inet_pton进行相反的转换,从数值格式(addrptr)转换到表达格式(strptr)。
函数尝试转换由strptr指针所指的字符串,并通过addrptr指针存放二进制结果。若成功则返回1,
否则如果对所指定的family而言输入的字符串不是有效的表达式,那么值为0。
返回:1——成功,0----输入不是有效的表达式,-1——出错;
inet_ntop进行相反的转换,从数值格式(addrptr)转换到表达格式(strptr)。
len参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。
返回:指向结果的指针——成功,NULL——出错;
*/
cout<<"host.c_str"<<host.c_str()<<endl;
cout<<"inet_pton"<<endl;
iRet = inet_pton(AF_INET, host.c_str(), &sock_addr.sin_addr);
if(1 != iRet)
{
return false;
}
sock_addr.sin_port = htons(30000);
//sock_addr.sin_addr.s_addr = inet_addr(host.c_str());
cout<<"connect server... host = "<<host.c_str()<<" port = "<<uiPort<<endl;
iRet = ::connect(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
if (0 != iRet)
{
cout<<"connect error"<<endl;
return false;
}
return true;
}
/**************************************************************************
* |
* Function Name : Socket.CloseSocket
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
VOID Socket::CloseSocket()
{
close(sockfd);
}
/**************************************************************************
* |
* Function Name : Socket.SetSocketNoblocking
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
INT Socket::SetSocketNoblocking(BOOL no)
{
int flags = 0;
int iret = 0;
flags = fcntl (sockfd, F_GETFL, 0);
if (flags == -1)
{
perror ("fcntl");
return -1;
}
if (no)
{
BIT_SET(flags, O_NONBLOCK);
}
else
{
BIT_RESET(flags, O_NONBLOCK);
}
iret = fcntl (sockfd, F_SETFL, flags);
if (iret == -1)
{
perror ("fcntl");
return iret;
}
}
/**************************************************************************
* |
* Function Name : Socket.Send
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
INT Socket::Send(const std::string &str)const
{
INT iSndLen = 0;
if (!Is_Valid())
{
return -1;
}
iSndLen = ::send(sockfd, str.c_str(), str.size(), 0);
if (iSndLen != str.size())
{
cout<<"send falied";
return -1;
}
return iSndLen;
}
/**************************************************************************
* |
* Function Name : Socket.Recv
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
INT Socket::Recv(std::string &str)const
{
CHAR Buff[BUFF_SIZE_1024];
INT iRcvLen = 0;
if (!Is_Valid())
{
return -1;
}
Buff[0] = '\0';
iRcvLen = ::recv(sockfd, Buff, BUFF_SIZE_1024, 0);
if (0 == iRcvLen)
{
cout<<"remote socket closed"<<endl;
}
else if (0 > iRcvLen)
{
cout<<"recv error "<<endl;
}
str = Buff;
return iRcvLen;
}
Server端继承Socket类
// Definition of the ServerSocket class
#ifndef ServerSocket_class
#define ServerSocket_class
#include "e_socket.h"
class ServerSocket : private Socket
{
public:
ServerSocket ( UINT port );
ServerSocket (){};
virtual ~ServerSocket();
const ServerSocket& operator << ( const std::string& ) const;
const ServerSocket& operator >> ( std::string& ) const;
void Accept ( ServerSocket& );
};
#endif
// Definition of the ServerSocket class
#include "e_server.h"
#include "SocketException.h"
ServerSocket::ServerSocket(UINT uiPort)
{
BOOL bRes = false;
bRes = Socket::CreateSocket();
if (false == bRes)
{
throw SocketException ( "Could not create server socket." );
}
bRes = Socket::BindSocket(uiPort);
if (false == bRes)
{
throw SocketException ( "Server Could not bind to port." );
}
bRes = Socket::ListenSocket();
if(false == bRes)
{
throw SocketException ( "Could not listen to socket." );
}
}
ServerSocket::~ServerSocket()
{
}
/**************************************************************************
* |
* Function Name : ServerSocket.Accept
* Input :
* Author : lily
* Date : 2018-8-26
* Description :
* Return :
* |
**************************************************************************/
void ServerSocket::Accept(ServerSocket &ser_skt)
{
cout<<"accept connect..."<<endl;
/* 子类对象可以直接通过值传递传给父类,反之则不行 */
if (!Socket::AcceptSocket(ser_skt))
{
throw SocketException ( "Could not accept socket." );
}
}
const ServerSocket& ServerSocket::operator << ( const std::string &str ) const
{
if (! Socket::Send(str))
{
throw SocketException ( "Could not write to socket." );
}
return *this;
}
const ServerSocket& ServerSocket::operator >> ( std::string& str ) const
{
if (! Socket::Recv(str))
{
throw SocketException ( "Could not read from socket." );
}
return *this;
}
Client 端继承Socket类
// Definition of the ClientSocket class
#ifndef ClientSocket_class
#define ClientSocket_class
#include "e_socket.h"
class ClientSocket : private Socket
{
public:
ClientSocket ( std::string host, UINT port );
virtual ~ClientSocket(){};
const ClientSocket& operator << ( const std::string& ) const;
const ClientSocket& operator >> ( std::string& ) const;
};
#endif
// Implementation of the ClientSocket class
#include "e_client.h"
#include "SocketException.h"
ClientSocket::ClientSocket ( std::string host, UINT port )
{
if ( ! Socket::CreateSocket() )
{
throw SocketException ( "Could not create client socket." );
}
if ( ! Socket::ConnectSocket(host, port))
{
throw SocketException ( "Could not connect to server." );
}
}
const ClientSocket& ClientSocket::operator << ( const std::string& s ) const
{
if ( ! Socket::Send(s) )
{
throw SocketException ( "Could not write to socket." );
}
return *this;
}
const ClientSocket& ClientSocket::operator >> ( std::string& s ) const
{
if ( ! Socket::Recv(s) )
{
throw SocketException ( "Could not read from socket." );
}
return *this;
}
服务器主函数部分 :
#include "SocketException.h"
#include "e_server.h"
int main ( int argc, char *argv[] )
{
std::cout << "running....\n";
try
{
// Create the socket
ServerSocket server ( 30000 );
while ( true )
{
ServerSocket new_sock;
server.Accept(new_sock);
try
{
while ( true )
{
std::string data;
new_sock >> data;/* operator << */
new_sock << data;/* operator >> */
}
}
catch ( SocketException& )
{
}
}
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
客户端主函数部分:
#include "e_client.h"
#include "SocketException.h"
#include <iostream>
#include <string>
int main ( int argc, char *argv[] )
{
try
{
ClientSocket client_socket ( "127.0.0.1", 30000 );
std::string reply;
try
{
client_socket << "Test message.";
client_socket >> reply;
}
catch ( SocketException& ) {}
std::cout << "We received this response from the server:\n\"" << reply << "\"\n";;
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\n";
}
return 0;
}
异常处理类
// SocketException class
#ifndef SocketException_class
#define SocketException_class
#include <string>
class SocketException
{
public:
SocketException ( std::string s ) : m_s ( s ) {};
~SocketException (){};
std::string description() { return m_s; }
private:
std::string m_s;
};
#endif
效果:
客户端
li@li:~/C++/socket/client$ ./a.out
host.c_str127.0.0.1
inet_pton
connect server... host = 127.0.0.1 port = 30000
We received this response from the server:
"Test message."
服务器:
li@li:~/C++/socket/server$ ./a.out
running....
server bind socket ...
listening ...
accept connect...
remote socket closed
后续会在此基础上改进,并新增EPOLL类,丰富服务器处理类型