Back

Socket_Cpp库的使用

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议

20190623_tcp_termination.png (925×613) (linuxblogs.cn)

此库是一个简单的TCP库👉sockpp

TCP

TCP Clien

IPV4:tcp_clien

sockpp::socket_initializer sockpp环境初始化

sockpp::tcp_connector conn({host, port}) // 初始化一个连接器,并尝试连接到{host, port}
    !conn.read_timeout(seconds(5)) // 读超时
    conn.address() // 连接成功打印地址

conn.connect(sockpp::inet_address("localhost", port)) // 链接{localhost, port}
	sockpp::inet_address(host, port) // 返回一个默认的端口号和地址
conn.clone() // clone一个sockpp::tcp_socket
conn.last_error_str() // 返回根据平台各自的错误字符串
conn.last_error()
conn.write(s) // 通过coon把字符串s写过去
conn.write_n(buf, n) // 从buf中取n个字节的数据并通过tcp写过去
conn.read(buf, sizeof(buf))) // 读sizeof(buf)个字节到buf中,并返回读到的字节数
conn.read_n() // 
conn.address() // 服务器的地址
conn.peer_address()
conn.shutdown(SHUT_WR)

例子- 单线程

#include <iostream>
#include <string>
#include "sockpp/tcp_connector.h"
#include "sockpp/version.h"

using namespace std;
using namespace std::chrono;

int main(int argc, char* argv[]) {
	cout << "Sample TCP echo client for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	string host = (argc > 1) ? argv[1] : "localhost";
	in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;

	sockpp::socket_initializer sockInit;

	// Implicitly creates an inet_address from {host,port}
	// and then tries the connection.

	sockpp::tcp_connector conn({host, port});
	if (!conn) {
		cerr << "Error connecting to server at "
			<< sockpp::inet_address(host, port)
			<< "\n\t" << conn.last_error_str() << endl;
		return 1;
	}

	cout << "Created a connection from " << conn.address() << endl;
	cout << "Created a connection to " << conn.peer_address() << endl;
    
    // Set a timeout for the responses
    if (!conn.read_timeout(seconds(5))) {
        cerr << "Error setting timeout on TCP stream: "
                << conn.last_error_str() << endl;
    }

	string s, sret;
	while (getline(cin, s) && !s.empty()) {
		if (conn.write(s) != ssize_t(s.length())) {
			cerr << "Error writing to the TCP stream: "
				<< conn.last_error_str() << endl;
			break;
		}

		sret.resize(s.length());
		ssize_t n = conn.read_n(&sret[0], s.length());

		if (n != ssize_t(s.length())) {
			cerr << "Error reading from TCP stream: "
				<< conn.last_error_str() << endl;
			break;
		}

		cout << sret << endl;
	}

	return (!conn) ? 1 : 0;
}

IPV6:tcp6_clien

sockpp::tcp6_connector conn({host, port});
	sockpp::inet6_address(host, port);
conn.last_error_str();
conn.read_timeout(seconds(5));
conn.last_error_str();
conn.write(s);

例子

#include <iostream>
#include <string>
#include "sockpp/tcp6_connector.h"
#include "sockpp/version.h"

using namespace std;
using namespace std::chrono;

// --------------------------------------------------------------------------

int main(int argc, char* argv[]) {
	cout << "Sample IPv6 TCP echo client for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	std::string host = (argc > 1) ? argv[1] : "::1";
	in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;

	sockpp::socket_initializer sockInit;

	// Implicitly creates an inet6_address from {host,port}
	// and then tries the connection.

	sockpp::tcp6_connector conn({host, port});
	if (!conn) {
		cerr << "Error connecting to server at "
			<< sockpp::inet6_address(host, port)
			<< "\n\t" << conn.last_error_str() << endl;
		return 1;
	}

	cout << "Created a connection from " << conn.address() << endl;
	cout << "Created a connection to " << conn.peer_address() << endl;
    
    // Set a timeout for the responses
    if (!conn.read_timeout(seconds(5))) {
        cerr << "Error setting timeout on TCP stream: "
                << conn.last_error_str() << endl;
    }

	string s, sret;
	while (getline(cin, s) && !s.empty()) {
		if (conn.write(s) != ssize_t(s.length())) {
			cerr << "Error writing to the TCP stream: "
				<< conn.last_error_str() << endl;
			break;
		}

		sret.resize(s.length());
		ssize_t n = conn.read_n(&sret[0], s.length());

		if (n != ssize_t(s.length())) {
			cerr << "Error reading from TCP stream: "
				<< conn.last_error_str() << endl;
			break;
		}

		cout << sret << endl;
	}

	return (!conn) ? 1 : 0;
}

TCP Server

IPV4:tcp_server

sockpp::tcp_acceptor acc(port) // 绑定port,并创建一个sockpp::tcp_socket的acc
sockpp::tcp_socket sock = acc.accept(&peer) // 接受一个tcp连接并返回sockpp::tcp_socket

例子-多线程

#include <iostream>
#include <thread>
#include "sockpp/tcp_acceptor.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------
// The thread function. This is run in a separate thread for each socket.
// Ownership of the socket object is transferred to the thread, so when this
// function exits, the socket is automatically closed.

void run_echo(sockpp::tcp_socket sock) {
	ssize_t n;
	char buf[512];

	while ((n = sock.read(buf, sizeof(buf))) > 0)
		sock.write_n(buf, n);

	cout << "Connection closed from " << sock.peer_address() << endl;
}

// --------------------------------------------------------------------------
// The main thread runs the TCP port acceptor. Each time a connection is
// made, a new thread is spawned to handle it, leaving this main thread to
// immediately wait for the next connection.

int main(int argc, char* argv[]) {
	cout << "Sample TCP echo server for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;

	sockpp::socket_initializer sockInit;

	sockpp::tcp_acceptor acc(port);

	if (!acc) {
		cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
		return 1;
	}
    //cout << "Acceptor bound to address: " << acc.address() << endl;
	cout << "Awaiting connections on port " << port << "..." << endl;

	while (true) {
		sockpp::inet_address peer;

		// Accept a new client connection
		sockpp::tcp_socket sock = acc.accept(&peer);
		cout << "Received a connection request from " << peer << endl;

		if (!sock) {
			cerr << "Error accepting incoming connection: " 
				<< acc.last_error_str() << endl;
		}
		else {
			// Create a thread and transfer the new stream to it.
			thread thr(run_echo, std::move(sock));
			thr.detach();
		}
	}

	return 0;
}

IPV6:tcp6_server

sockpp::tcp6_acceptor acc(port);
sockpp::inet6_address peer;
acc.accept(&peer);

例子 - 多线程

#include <iostream>
#include <thread>
#include "sockpp/tcp6_acceptor.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------
// The thread function. This is run in a separate thread for each socket.
// Ownership of the socket object is transferred to the thread, so when this
// function exits, the socket is automatically closed.

void run_echo(sockpp::tcp6_socket sock) {
	ssize_t n;
	char buf[512];

    while ((n = sock.read(buf, sizeof(buf))) > 0)
		sock.write_n(buf, n);

	cout << "Connection closed from " << sock.peer_address() << endl;
}

// --------------------------------------------------------------------------
// The main thread runs the TCP port acceptor. Each time a connection is
// made, a new thread is spawned to handle it, leaving this main thread to
// immediately wait for the next connection.

int main(int argc, char* argv[]) {
	cout << "Sample IPv6 TCP echo server for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;

	sockpp::socket_initializer sockInit;
	sockpp::tcp6_acceptor acc(port);

	if (!acc) {
		cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
		return 1;
	}
	cout << "Awaiting connections on port " << port << "..." << endl;

	while (true) {
		sockpp::inet6_address peer;

		// Accept a new client connection
		sockpp::tcp6_socket sock = acc.accept(&peer);
		cout << "Received a connection request from " << peer << endl;

		if (!sock) {
			cerr << "Error accepting incoming connection: " 
				<< acc.last_error_str() << endl;
		}
		else {
			// Create a thread and transfer the new stream to it.
			thread thr(run_echo, std::move(sock));
			thr.detach();
		}
	}

	return 0;
}

UDP

UDP Clien

IPV4:udp_clien

sockpp::socket_initializer sockInit;

sockpp::udp_socket sock;
sock.connect(sockpp::inet_address(host, port));
	sock.last_error_str();
      
sockpp::inet_address addr("localhost", 12345);
sock.send(s);
sock.send_to(msg, addr);

char buf[16];
ssize_t n = sock.recv(buf, sizeof(buf), &srcAddr);

例子:

#include <iostream>
#include <string>
#include "sockpp/udp_socket.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------

int main(int argc, char* argv[]) {
	cout << "Sample UDP echo client for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	string host = (argc > 1) ? argv[1] : "localhost";
	in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;

	sockpp::socket_initializer sockInit;

	sockpp::udp_socket sock;

	if (!sock.connect(sockpp::inet_address(host, port))) {
		cerr << "Error connecting to server at " << host << ":" << port 
			<< "\n\t" << sock.last_error_str() << endl;
		return 1;
	}

	cout << "Created UDP socket at: " << sock.address() << endl;

	string s, sret;
	while (getline(cin, s) && !s.empty()) {
		if (sock.send(s) != ssize_t(s.length())) {
			cerr << "Error writing to the UDP socket: "
				<< sock.last_error_str() << endl;
			break;
		}

		sret.resize(s.length());
		ssize_t n = sock.recv(&sret[0], s.length());

		if (n != ssize_t(s.length())) {
			cerr << "Error reading from UDP socket: "
				<< sock.last_error_str() << endl;
			break;
		}

		cout << sret << endl;
	}

	return (!sock) ? 1 : 0;
}

IPV6:udp6_clien

sockpp::socket_initializer sockInit;

sockpp::udp6_socket sock;
sock.connect(sockpp::inet6_address(host, port));
	sock.last_error_str();
sock.address();
sock.send(s);
sock.recv(&sret[0], s.length());

例子

#include <iostream>
#include <string>
#include "sockpp/udp6_socket.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------

int main(int argc, char* argv[]) {
	cout << "Sample IPv6 UDP echo client for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	string host = (argc > 1) ? argv[1] : "localhost";
	in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;

	sockpp::socket_initializer sockInit;

	sockpp::udp6_socket sock;

	if (!sock.connect(sockpp::inet6_address(host, port))) {
		cerr << "Error connecting to server at " << host << ":" << port 
			<< "\n\t" << sock.last_error_str() << endl;
		return 1;
	}

	cout << "Created UDP socket at: " << sock.address() << endl;

	string s, sret;
	while (getline(cin, s) && !s.empty()) {
		if (sock.send(s) != ssize_t(s.length())) {
			cerr << "Error writing to the UDP socket: "
				<< sock.last_error_str() << endl;
			break;
		}

		sret.resize(s.length());
		ssize_t n = sock.recv(&sret[0], s.length());

		if (n != ssize_t(s.length())) {
			cerr << "Error reading from UDP socket: "
				<< sock.last_error_str() << endl;
			break;
		}

		cout << sret << endl;
	}

	return (!sock) ? 1 : 0;
}

UDP Server

IPV4:udp_server

sockpp::socket_initializer sockInit;
sockpp::udp_socket	udpsock;
udpsock.bind(sockpp::inet_address("localhost", port));
udpsock.last_error_str();

例子:

#include <iostream>
#include <thread>
#include "sockpp/udp_socket.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------
// The thread function. This is run in a separate thread for each socket.
// Ownership of the socket object is transferred to the thread, so when this
// function exits, the socket is automatically closed.

template <typename UDPSOCK>
void run_echo(UDPSOCK sock) {
	ssize_t n;
	char buf[512];

	// Each UDP socket type knows its address type as `addr_t`
	typename UDPSOCK::addr_t srcAddr;

	// Read some data, also getting the address of the sender,
	// then just send it back.
	while ((n = sock.recv_from(buf, sizeof(buf), &srcAddr)) > 0)
		sock.send_to(buf, n, srcAddr);
}

// --------------------------------------------------------------------------
// The main thread creates the two UDP sockets (one each for IPv4 and IPv6),
// and then starts them running the echo function each in a separate thread.

int main(int argc, char* argv[]) {
	cout << "Sample UDP echo server for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;

	sockpp::socket_initializer sockInit;

	sockpp::udp_socket	udpsock;
	if (!udpsock) {
		cerr << "Error creating the UDP v4 socket: " << udpsock.last_error_str() << endl;
		return 1;
	}

	if (!udpsock.bind(sockpp::inet_address("localhost", port))) {
		cerr << "Error binding the UDP v4 socket: " << udpsock.last_error_str() << endl;
		return 1;
	}

	// Spin up a thread to run the IPv4 socket.
	thread thr(run_echo<sockpp::udp_socket>, std::move(udpsock));
	thr.detach();

	return 0;
}

IPV6:udp6_server

sockpp::socket_initializer sockInit;
sockpp::udp6_socket	udp6sock;
udp6sock.last_error_str();
udp6sock.bind(sockpp::inet6_address("localhost", port));

例子:

#include <iostream>
#include <thread>
#include "sockpp/udp6_socket.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------
// The thread function. This is run in a separate thread for each socket.
// Ownership of the socket object is transferred to the thread, so when this
// function exits, the socket is automatically closed.

template <typename UDPSOCK>
void run_echo(UDPSOCK sock) {
	ssize_t n;
	char buf[512];

	// Each UDP socket type knows its address type as `addr_t`
	typename UDPSOCK::addr_t srcAddr;

	// Read some data, also getting the address of the sender,
	// then just send it back.
	while ((n = sock.recv_from(buf, sizeof(buf), &srcAddr)) > 0)
		sock.send_to(buf, n, srcAddr);
}

// --------------------------------------------------------------------------
// The main thread creates the two UDP sockets (one each for IPv4 and IPv6),
// and then starts them running the echo function each in a separate thread.

int main(int argc, char* argv[]) {
	cout << "Sample UDP echo server for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;

	sockpp::socket_initializer sockInit;

	sockpp::udp6_socket	udp6sock;
	if (!udp6sock) {
		cerr << "Error creating the UDP v6 socket: " << udp6sock.last_error_str() << endl;
		return 1;
	}

	if (!udp6sock.bind(sockpp::inet6_address("localhost", port))) {
		cerr << "Error binding the UDP v6 socket: " << udp6sock.last_error_str() << endl;
		return 1;
	}

	// Spin up a thread to run the IPv4 socket.
	thread thr(run_echo<sockpp::udp6_socket>, std::move(udp6sock));
	thr.detach();

	return 0;
}

UNIX

UNIX Clien

sockpp::socket_initializer sockInit;

sockpp::unix_connector conn;
conn.connect(sockpp::unix_address(path));
conn.last_error_str();
conn.peer_address();

例子:

#include <iostream>
#include <string>
#include "sockpp/unix_connector.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------

int main(int argc, char* argv[]) {
	cout << "Sample Unix-domain echo client for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	string path = (argc > 1) ? argv[1] : "/tmp/unechosvr.sock";

	sockpp::socket_initializer sockInit;

	sockpp::unix_connector conn;

    bool ok = conn.connect(sockpp::unix_address(path));
	if (!ok) {
		cerr << "Error connecting to UNIX socket at " << path
			<< "\n\t" << conn.last_error_str() << endl;
		return 1;
	}

	cout << "Created a connection to '" << conn.peer_address() << "'" << endl;

	string s, sret;
	while (getline(cin, s) && !s.empty()) {
		if (conn.write(s) != (int) s.length()) {
			cerr << "Error writing to the UNIX stream" << endl;
			break;
		}

		sret.resize(s.length());
		int n = conn.read_n(&sret[0], s.length());

		if (n != (int) s.length()) {
			cerr << "Error reading from UNIX stream" << endl;
			break;
		}

		cout << sret << endl;
	}

	return (!conn) ? 1 : 0;
}

UNIX Server

sockpp::socket_initializer sockInit;
sockpp::unix_acceptor acc;
acc.open(sockpp::unix_address(path));
acc.last_error_str();
acc.address();
acc.accept();

例子 - 多线程

#include <iostream>
#include <thread>
#include "sockpp/unix_acceptor.h"
#include "sockpp/version.h"

using namespace std;

// --------------------------------------------------------------------------
// The thread function. This is run in a separate thread for each socket.
// Ownership of the socket object is transferred to the thread, so when this
// function exits, the socket is automatically closed.

void run_echo(sockpp::unix_socket sock) {
	int n;
	char buf[512];

	while ((n = sock.read(buf, sizeof(buf))) > 0)
		sock.write_n(buf, n);

	cout << "Connection closed" << endl;
}

// --------------------------------------------------------------------------
// The main thread runs the UNIX acceptor.
// Each time a connection is made, a new thread is spawned to handle it,
// leaving this main thread to immediately wait for the next connection.

int main(int argc, char* argv[]) {
	cout << "Sample Unix-domain echo server for 'sockpp' "
		<< sockpp::SOCKPP_VERSION << '\n' << endl;

	string path = "/tmp/unechosvr.sock";

	if (argc > 1) {
		path = argv[1];
	}

	sockpp::socket_initializer sockInit;
	sockpp::unix_acceptor acc;

	bool ok = acc.open(sockpp::unix_address(path));

	if (!ok) {
		cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
		return 1;
	}
    cout << "Acceptor bound to address: '" << acc.address() << "'..." << endl;

	while (true) {
		// Accept a new client connection
		auto sock = acc.accept();
		cout << "Received a connection" << endl;

		if (!sock) {
			cerr << "Error accepting incoming connection: " 
				<< acc.last_error_str() << endl;
		} else {
			// Create a thread and transfer the new stream to it.
			thread thr(run_echo, std::move(sock));
			thr.detach();
		}
	}

	return 0;
}