Programming Tips blog

テキトーにTIPSを紹介します

ラズパイでソケット通信(C++サーバ - Pythonクライアント)

C++サーバ

cmake

# CMakeのバージョンを設定
cmake_minimum_required(VERSION 3.25)
enable_language(CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Threads REQUIRED)

# プロジェクト名と使用する言語を設定
project(servertest CXX)

# 取り込むソースコード
set(server_src
	servertest04.cpp
)

# おまじない
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-long-long -pedantic")

# servertestという実行ファイルをserver_srcから作成
add_executable(servertest ${server_src})

# スレッドへリンク
target_link_libraries(servertest Threads::Threads)

C++

#include <iostream>
#include <thread>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>

void BridgeConnectionThread(int connection_socket) {
	char buffer[1024] = {0};
	const char *ack = "ACK";
	int16_t i = 0;
	
	while(true) {
		// データを受信する
		int received_size = recv(connection_socket, buffer, sizeof(buffer), 0);
		// 相手からcloseがコールされた場合
		if(received_size == 0) {
			std::cout << i << "Close" << std::endl;
			break;
		}
		// recvでエラーが発生した場合
		else if(received_size < 0) {
			std::cerr << "Clushed Connection" << std::endl;
			close(connection_socket);
			return;
		}
		
		// char[]をstringに変換する
		std::string buff(buffer, sizeof(buffer) / sizeof(buffer[0]));
		
		// 送られてきたメッセージを表示する
		std::cout << i << "Message from client:" << buff << std::endl;
		
		// データを送信する
		send(connection_socket, ack, strlen(ack), 0);
		std::cout << "send ACK" << std::endl;
		
		i++;
	}
	// コネクションソケットをcloseする
	close(connection_socket);
	return;
}

int main() {
	int server_socket, connection_socket;
	struct sockaddr_in server_address, connection_address;
	socklen_t addrSize;
//	int addrlen = sizeof(address);
//	std::vector<std::thread> threads;
	
	// socket
	server_socket = socket(AF_INET, SOCK_STREAM, 0);
	if(server_socket == -1) {
		std::cerr << "Socket creation failed" << std::endl;
		exit(1);
	}
	
	// アドレスの準備
	server_address.sin_family = AF_INET;
	server_address.sin_addr.s_addr = htonl(INADDR_ANY);
	server_address.sin_port = htons(2345);
	
	// bind
	if(bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) != 0) {
		std::cerr << "Socket bind failed" << std::endl;
		exit(1);
	}
	
	// listen
	if(listen(server_socket, 5) != 0) {
		std::cerr << "Listen failed" << std::endl;
		exit(1);
	}
	
	while(true) {
		addrSize = sizeof(connection_address);
		connection_socket = accept(server_socket, (struct sockaddr *)&connection_address, (socklen_t*)&addrSize);
		if(connection_socket < 0) {
			continue;
		}
		std::thread ConnectionThread(BridgeConnectionThread, connection_socket);
		ConnectionThread.detach();
	}
	
	close(server_socket);
	return 0;
}

Pythonクライアント

#!/usr/bin/python3
# -*- coding: utf-8 -*-


import socket
import time


# メイン関数
# 引数:なし
# 返値:なし
def main():
	# 変数定義、初期化
	server_address = "127.0.0.1"	# サーバIPアドレス
	server_port = 2345				# サーバポート番号
	recv_buffer = 1024				# 受信バッファサイズ
	message = "Hello World!"		# 送信文字列
	data = ""						# 受信文字列
	
	# クライアントソケット作成
	client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	
	# サーバに接続する
	client_socket.connect((server_address, server_port))
	
	for i in range(50):
		# メッセージを送信する
		client_socket.send((str(i) + ":" + message).encode("utf-8"))
		# 確認応答メッセージを受信する
		data = client_socket.recv(recv_buffer).decode("utf-8")
		print(str(i) + ":" + data)
	
	# クライアントソケットをcloseする
	client_socket.close()
	return


# メイン関数
# 引数:なし
# 返値:なし
# 備考:main()に投げるだけ
if __name__ == "__main__":
	main()