C++
クライアントサーバーの例
サーチ…
ハローTCPサーバー
最初にBeej's Guide to Network Programmingを読んで、それをすばやく読んで、この資料のほとんどをもう少し詳しく説明する必要があると言います。ここでは、すべての着信接続に対して「Hello World」と言う単純なTCPサーバーを作成して閉じます。注意すべきもう一つのことは、サーバーがクライアントと繰り返し通信することです。これは一度に1つのクライアントを意味します。それぞれの関数呼び出しとソケット構造に関する貴重な情報が含まれている可能性があるので、関連するマニュアルページを必ずチェックしてください。
ポートでサーバーを実行するので、ポート番号の引数も取ります。コードを使い始める -
#include <cstring> // sizeof()
#include <iostream>
#include <string>
// headers for socket(), getaddrinfo() and friends
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // close()
int main(int argc, char *argv[])
{
// Let's check if port number is supplied or not..
if (argc != 2) {
std::cerr << "Run program as 'program <port>'\n";
return -1;
}
auto &portNum = argv[1];
const unsigned int backLog = 8; // number of connections allowed on the incoming queue
addrinfo hints, *res, *p; // we need 2 pointers, res to hold and p to iterate over
memset(&hints, 0, sizeof(hints));
// for more explanation, man socket
hints.ai_family = AF_UNSPEC; // don't specify which IP version to use yet
hints.ai_socktype = SOCK_STREAM; // SOCK_STREAM refers to TCP, SOCK_DGRAM will be?
hints.ai_flags = AI_PASSIVE;
// man getaddrinfo
int gAddRes = getaddrinfo(NULL, portNum, &hints, &res);
if (gAddRes != 0) {
std::cerr << gai_strerror(gAddRes) << "\n";
return -2;
}
std::cout << "Detecting addresses" << std::endl;
unsigned int numOfAddr = 0;
char ipStr[INET6_ADDRSTRLEN]; // ipv6 length makes sure both ipv4/6 addresses can be stored in this variable
// Now since getaddrinfo() has given us a list of addresses
// we're going to iterate over them and ask user to choose one
// address for program to bind to
for (p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer;
// if address is ipv4 address
if (p->ai_family == AF_INET) {
ipVer = "IPv4";
sockaddr_in *ipv4 = reinterpret_cast<sockaddr_in *>(p->ai_addr);
addr = &(ipv4->sin_addr);
++numOfAddr;
}
// if address is ipv6 address
else {
ipVer = "IPv6";
sockaddr_in6 *ipv6 = reinterpret_cast<sockaddr_in6 *>(p->ai_addr);
addr = &(ipv6->sin6_addr);
++numOfAddr;
}
// convert IPv4 and IPv6 addresses from binary to text form
inet_ntop(p->ai_family, addr, ipStr, sizeof(ipStr));
std::cout << "(" << numOfAddr << ") " << ipVer << " : " << ipStr
<< std::endl;
}
// if no addresses found :(
if (!numOfAddr) {
std::cerr << "Found no host address to use\n";
return -3;
}
// ask user to choose an address
std::cout << "Enter the number of host address to bind with: ";
unsigned int choice = 0;
bool madeChoice = false;
do {
std::cin >> choice;
if (choice > (numOfAddr + 1) || choice < 1) {
madeChoice = false;
std::cout << "Wrong choice, try again!" << std::endl;
} else
madeChoice = true;
} while (!madeChoice);
p = res;
// let's create a new socket, socketFD is returned as descriptor
// man socket for more information
// these calls usually return -1 as result of some error
int sockFD = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockFD == -1) {
std::cerr << "Error while creating socket\n";
freeaddrinfo(res);
return -4;
}
// Let's bind address to our socket we've just created
int bindR = bind(sockFD, p->ai_addr, p->ai_addrlen);
if (bindR == -1) {
std::cerr << "Error while binding socket\n";
// if some error occurs, make sure to close socket and free resources
close(sockFD);
freeaddrinfo(res);
return -5;
}
// finally start listening for connections on our socket
int listenR = listen(sockFD, backLog);
if (listenR == -1) {
std::cerr << "Error while Listening on socket\n";
// if some error occurs, make sure to close socket and free resources
close(sockFD);
freeaddrinfo(res);
return -6;
}
// structure large enough to hold client's address
sockaddr_storage client_addr;
socklen_t client_addr_size = sizeof(client_addr);
const std::string response = "Hello World";
// a fresh infinite loop to communicate with incoming connections
// this will take client connections one at a time
// in further examples, we're going to use fork() call for each client connection
while (1) {
// accept call will give us a new socket descriptor
int newFD
= accept(sockFD, (sockaddr *) &client_addr, &client_addr_size);
if (newFD == -1) {
std::cerr << "Error while Accepting on socket\n";
continue;
}
// send call sends the data you specify as second param and it's length as 3rd param, also returns how many bytes were actually sent
auto bytes_sent = send(newFD, response.data(), response.length(), 0);
close(newFD);
}
close(sockFD);
freeaddrinfo(res);
return 0;
}
次のプログラムは -
Detecting addresses
(1) IPv4 : 0.0.0.0
(2) IPv6 : ::
Enter the number of host address to bind with: 1
ハローTCPクライアント
このプログラムは、Hello TCP Serverプログラムと相補的です。お互いの正当性をチェックするためにどちらかを実行することができます。プログラムの流れは、Hello TCPサーバではよくあることですので、あまりにもそれを見てください。
ここにコードがあります -
#include <cstring>
#include <iostream>
#include <string>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// Now we're taking an ipaddress and a port number as arguments to our program
if (argc != 3) {
std::cerr << "Run program as 'program <ipaddress> <port>'\n";
return -1;
}
auto &ipAddress = argv[1];
auto &portNum = argv[2];
addrinfo hints, *p;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int gAddRes = getaddrinfo(ipAddress, portNum, &hints, &p);
if (gAddRes != 0) {
std::cerr << gai_strerror(gAddRes) << "\n";
return -2;
}
if (p == NULL) {
std::cerr << "No addresses found\n";
return -3;
}
// socket() call creates a new socket and returns it's descriptor
int sockFD = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockFD == -1) {
std::cerr << "Error while creating socket\n";
return -4;
}
// Note: there is no bind() call as there was in Hello TCP Server
// why? well you could call it though it's not necessary
// because client doesn't necessarily has to have a fixed port number
// so next call will bind it to a random available port number
// connect() call tries to establish a TCP connection to the specified server
int connectR = connect(sockFD, p->ai_addr, p->ai_addrlen);
if (connectR == -1) {
close(sockFD);
std::cerr << "Error while connecting socket\n";
return -5;
}
std::string reply(15, ' ');
// recv() call tries to get the response from server
// BUT there's a catch here, the response might take multiple calls
// to recv() before it is completely received
// will be demonstrated in another example to keep this minimal
auto bytes_recv = recv(sockFD, &reply.front(), reply.size(), 0);
if (bytes_recv == -1) {
std::cerr << "Error while receiving bytes\n";
return -6;
}
std::cout << "\nClient recieved: " << reply << std::endl;
close(sockFD);
freeaddrinfo(p);
return 0;
}
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow