原理不再赘述
文件构成:
client.cpp
client_socket.cpp
client_socket.h
Makefile
server.cpp
server_socket.cpp
server_socket.h
socket.cpp
socket_exception.h
socket.h
1.socket.h文件 主要实现基类
#ifndef SOCKET_H
#define SOCKET_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
const int MAXHOSTNAME = 200;
const int MAXCONNECTIONS = 5;
const int MAXRECV = 500;
class Socket
{
public:
Socket();
virtual ~Socket();
// Server initialization
bool create();
bool bind ( const int port );
bool listen() const;
bool accept ( Socket& ) const;
// Client initialization
bool connect ( const std::string host, const int port );
// Data Transimission
bool send ( const std::string ) const;
int recv ( std::string& ) const;
void set_non_blocking ( const bool );
bool is_valid() const
{
return m_sock != -1;
}
private:
int m_sock;
sockaddr_in m_addr;
};
2.socket.cpp
#include "socket.h"
#include <iostream>
#include <string>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>
using namespace std;
Socket::Socket() : m_sock ( -1 )
{
memset ( &m_addr, 0, sizeof ( m_addr ) );
}
Socket::~Socket()
{
if ( is_valid() )::close ( m_sock );
}
bool Socket::create()
{
m_sock = socket ( AF_INET, SOCK_STREAM, 0 );
if ( ! is_valid() )
return false;
// TIME_WAIT - argh
int on = 1;
if ( setsockopt ( m_sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 )
return false;
return true;
}
bool Socket::bind ( const int port )
{
if ( ! is_valid() )
{
return false;
}
m_addr.sin_family = AF_INET;
m_addr.sin_addr.s_addr = INADDR_ANY;
m_addr.sin_port = htons ( port );
int bind_return = ::bind ( m_sock, ( struct sockaddr * ) &m_addr, sizeof ( m_addr ) );
if ( bind_return == -1 )
{
return false;
}
return true;
}
bool Socket::listen() const
{
if ( ! is_valid() )
{
return false;
}
int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
if ( listen_return == -1 )
{
return false;
}
return true;
}
bool Socket::accept ( Socket& new_socket ) const
{
int addr_length = sizeof ( m_addr );
new_socket.m_sock = ::accept ( m_sock, ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
if ( new_socket.m_sock <= 0 )
return false;
else
return true;
}
bool Socket::send ( const std::string s ) const
{
int status = ::send ( m_sock, s.c_str(), s.size(), MSG_NOSIGNAL );
if ( status == -1 )
{
return false;
}
else
{
return true;
}
}
int Socket::recv ( std::string& s ) const
{
char buf [ MAXRECV + 1 ];
s = "";
memset ( buf, 0, MAXRECV + 1 );
int status = ::recv ( m_sock, buf, MAXRECV, 0 );
if ( status == -1 )
{
cout << "status == -1 errno == " << errno << " in Socket::recv\n";
return 0;
}
else if ( status == 0 )
{
return 0;
}
else
{
s = buf;
return status;
}
}
bool Socket::connect ( const std::string host, const int port )
{
if ( ! is_valid() ) return false;
m_addr.sin_family = AF_INET;
m_addr.sin_port = htons ( port );
int status = inet_pton ( AF_INET, host.c_str(), &m_addr.sin_addr );
if ( errno == EAFNOSUPPORT ) return false;
status = ::connect ( m_sock, ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
if ( status == 0 )
return true;
else
return false;
}
void Socket::set_non_blocking ( const bool b )
{
int opts;
opts = fcntl ( m_sock,
F_GETFL );
if ( opts < 0 )
{
return;
}
if ( b )
opts = ( opts | O_NONBLOCK );
else
opts = ( opts & ~O_NONBLOCK );
fcntl ( m_sock,
F_SETFL,opts );
}
3.sock_exception.h文件
#ifndef SOCKET_EXCEPTION_H
#define SOCKET_EXCEPTION_H
#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
4.server_socket.h文件
#ifndef SERVER_SOCKET_H
#define SERVER_SOCKET_H
#include "socket.h"
class ServerSocket : private Socket
{
public:
ServerSocket ( int port );
ServerSocket () {};
virtual ~ServerSocket();
const ServerSocket& operator << ( const std::string& ) const;
const ServerSocket& operator >> ( std::string& ) const;
void accept ( ServerSocket& );
};
#endif
5.server_socket.cpp文件
#include "server_socket.h"
#include "socket_exception.h"
ServerSocket::ServerSocket ( int port )
{
if ( ! Socket::create() )
{
throw SocketException ( "Could not create server socket." );
}
if ( ! Socket::bind ( port ) )
{
throw SocketException ( "Could not bind to port." );
}
if ( ! Socket::listen() )
{
throw SocketException ( "Could not listen to socket." );
}
}
ServerSocket::~ServerSocket()
{
}
const ServerSocket& ServerSocket::operator << ( const std::string& s ) const
{
if ( ! Socket::send ( s ) )
{
throw SocketException ( "Could not write to socket." );
}
return *this;
}
const ServerSocket& ServerSocket::operator >> ( std::string& s ) const
{
if ( ! Socket::recv ( s ) )
{
throw SocketException ( "Could not read from socket." );
}
return *this;
}
void ServerSocket::accept ( ServerSocket& sock )
{
if ( ! Socket::accept ( sock ) )
{
throw SocketException ( "Could not accept socket." );
}
}
6.server.cpp文件
#include "server_socket.h"
#include "socket_exception.h"
#include <string>
#include <iostream>
using namespace std;
int main ( int argc, char* argv[] )
{
std::cout << "running....\n" << std::endl;
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;
std::cout << "We received this response from the client:\n\"" << data << "\"\n";;
new_sock << data;
}
}
catch ( SocketException& ) {}
}
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
7.client_socket.h文件
#ifndef CLIENT_SOCKET_H
#define CLIENT_SOCKET_H
#include "socket.h"
class ClientSocket : private Socket
{
public:
ClientSocket ( std::string server_addr, int port );
virtual ~ClientSocket() {};
const ClientSocket& operator << ( const std::string& ) const;
const ClientSocket& operator >> ( std::string& ) const;
};
#endif
8.client_socket.cpp文件
#include "client_socket.h"
#include "socket_exception.h"
ClientSocket::ClientSocket ( std::string server_addr, int port )
{
if ( ! Socket::create() )
{
throw SocketException ( "Could not create client socket." );
}
if ( ! Socket::connect ( server_addr, port ) )
{
throw SocketException ( "Could not bind to port." );
}
}
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;
}
9.client.cpp文件
#include "client_socket.h"
#include "socket_exception.h"
#include <iostream>
#include <string>
using namespace std;
const string kServer_Address = "192.168.0.109";
int main ( int argc, char* argv[] )
{
try
{
ClientSocket client_socket ( kServer_Address, 30000 );
std::string reply;
try
{
if(argc == 2)
{
client_socket << argv[1];
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;
}
10.Makefile文件
all : simple_server simple_client
simple_server:socket.o server_socket.o server.o
g++ -o simple_server socket.o server_socket.o server.o
simple_client:socket.o client_socket.o client.o
g++ -o simple_client socket.o client_socket.o client.o
socket.o: socket.cpp socket.h
g++ -c socket.cpp
server_socket.o: server_socket.cpp server_socket.h socket_exception.h
g++ -c server_socket.cpp
client_socket.o: client_socket.cpp client_socket.h socket_exception.h
g++ -c client_socket.cpp
client.o:client.cpp
g++ -c client.cpp
server.o:server.cpp
g++ -c server.cpp
clean:
rm -f *.o simple_server simple_client
[jingsia@localhost socket]$ make
g++ -c socket.cpp
g++ -c server_socket.cpp
g++ -c server.cpp
g++ -o simple_server socket.o server_socket.o server.o
g++ -c client_socket.cpp
g++ -c client.cpp
g++ -o simple_client socket.o client_socket.o client.o
生成:
运行:
1.服务端启动
[jingsia@localhost socket]$ ./simple_server
running....
2.客户端发送消息至服务端
[jingsia@localhost socket]$ ./simple_client "simple socket test"
We received this response from the server:
"simple socket test"
3.服务器接收显示
[jingsia@localhost socket]$ ./simple_server
running....
We received this response from the client:
"simple socket test"
注意:
1.client设置服务器IP地址和端口号
源码可下载地址:https://github.com/jingsia/simple-socket-demo