UDP sample code add cmd and data
다른 PC에서 돌리고 cmd 4byte와 data 보내는 방식
아래는 B PC와 C PC 간의 UDP 통신을 위한 코드를 작성했습니다. 각 메시지는 command와 data로 구성되며, co
mmand는 고정 길이로 설정하고 data는 가변 길이로 설정했습니다. 이 방식은 향후 다른 command를 추가하기 쉽게 합니다
• B PC (C++): 포트 5002에서 수신하고 포트 5003으로 송신. 수신한 메시지의 첫 4바이트는 command, 나머지는 data.
• C PC (Python): 포트 5003에서 수신하고 포트 5002로 송신. 수신한 메시지의 첫 4바이트는 command, 나머지는 data.
이 코드에서는 command를 고정 길이 4바이트로 설정하여 메시지의 앞부분에 위치시키고, data는 가변 길이로 설정합니다.
이를 통해 메시지의 구성 요소를 쉽게 식별하고 처리할 수 있습니다.
udp_comm.cpp
#include <iostream>
#include <thread>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#define B_RECV_PORT 5002
#define C_SEND_PORT 5003
#define BUFFER_SIZE 1024
void receive_udp(int sockfd) {
char buffer[BUFFER_SIZE];
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
while (true) {
int n = recvfrom(sockfd, buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&cliaddr, &len);
if (n < 0) {
std::cerr << "recvfrom failed" << std::endl;
continue;
}
buffer[n] = '\0';
std::string sender_ip = inet_ntoa(cliaddr.sin_addr);
int sender_port = ntohs(cliaddr.sin_port);
// Extract command and data
std::string received(buffer);
std::string command = received.substr(0, 4);
std::string data = received.substr(4);
if (sender_port == C_SEND_PORT) {
std::cout << "Received message from C: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
} else {
std::cout << "Received message: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
}
}
}
void send_udp(int sockfd, const char* ip, int port) {
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
servaddr.sin_addr.s_addr = inet_addr(ip);
while (true) {
std::string command, data;
std::cout << "Enter command: ";
std::cin >> command;
std::cout << "Enter data: ";
std::cin >> data;
// Ensure command is 4 characters long
command.resize(4, ' ');
std::string message = command + data;
int n = sendto(sockfd, message.c_str(), message.size(), MSG_CONFIRM, (const struct sockaddr*)&servaddr, sizeof(servaddr));
if (n < 0) {
std::cerr << "sendto failed" << std::endl;
}
}
}
int main() {
int recv_sockfd, send_sockfd_c;
// 수신 소켓 생성 및 바인드
if ((recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Receive socket creation failed" << std::endl;
return -1;
}
struct sockaddr_in recvaddr;
memset(&recvaddr, 0, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_addr.s_addr = INADDR_ANY;
recvaddr.sin_port = htons(B_RECV_PORT);
if (bind(recv_sockfd, (const struct sockaddr*)&recvaddr, sizeof(recvaddr)) < 0) {
std::cerr << "Receive bind failed: " << strerror(errno) << std::endl;
close(recv_sockfd);
return -1;
}
// 송신 소켓 생성 (C)
if ((send_sockfd_c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Send socket creation failed" << std::endl;
close(recv_sockfd);
return -1;
}
std::thread recv_thread(receive_udp, recv_sockfd);
std::thread send_thread_c(send_udp, send_sockfd_c, "C_PC_IP", C_SEND_PORT); // C PC의 IP 주소로 설정
recv_thread.join();
send_thread_c.join();
close(recv_sockfd);
close(send_sockfd_c);
return 0;
}
udp_comm.python
import socket
import threading
class UdpComm:
def __init__(self, local_ip, local_port, remote_ip, remote_port):
self.local_ip = local_ip
self.local_port = local_port
self.remote_ip = remote_ip
self.remote_port = remote_port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((self.local_ip, self.local_port))
self.recv_thread = threading.Thread(target=self.receive_udp)
self.recv_thread.daemon = True
self.recv_thread.start()
def receive_udp(self):
while True:
data, addr = self.sock.recvfrom(1024) # 버퍼 크기 1024 바이트
self.on_receive(data.decode(), addr)
def send_data(self, command, data):
# Ensure command is 4 characters long
command = command.ljust(4)
message = command + data
self.sock.sendto(message.encode(), (self.remote_ip, self.remote_port))
def on_receive(self, message, addr):
command = message[:4]
data = message[4:]
print(f"Received message: Command: {command}, Data: {data} from {addr}")
# IP 주소와 포트 설정
local_ip = "0.0.0.0" # 모든 인터페이스에서 수신
local_port = 5003
remote_ip = "B_PC_IP" # B PC의 IP 주소
remote_port = 5002
# UdpComm 인스턴스 생성
udp_comm = UdpComm(local_ip, local_port, remote_ip, remote_port)
# 사용자 입력을 통한 데이터 송신
while True:
command = input("Enter command: ")
data = input("Enter data: ")
udp_comm.send_data(command, data)
refactoring
아래는 UdpComm 클래스를 상속받아 command와 data 처리를 커스터마이즈할 수 있도록 리팩토링한 코드입니다.
• UdpComm 클래스는 UDP 통신의 기본 기능을 제공합니다. 이 클래스는 수신한 데이터를 처리하는 on_receive 메서드를 가집니다.
• CustomUdpComm 클래스는 UdpComm 클래스를 상속받아 on_receive 메서드를 오버라이드하여 수신한 데이터를 커스터마이즈된 방식으로 처리합니다.
• main.cpp에서는 CustomUdpComm 인스턴스를 생성하고, command와 data를 전송 및 수신하는 기본 로직을 구현합니다.
이 구조를 통해 UdpComm 클래스의 기본 기능을 유지하면서, 수신한 데이터를 처리하는 방식을 쉽게 변경할 수 있습니다.
udp_comm.h
#ifndef UDPCOMM_HPP
#define UDPCOMM_HPP
#include <string>
#include <thread>
#include <arpa/inet.h>
class UdpComm {
public:
UdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port);
virtual ~UdpComm();
void start();
void stop();
void send_data(const std::string& command, const std::string& data);
protected:
virtual void on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port);
private:
void receive_udp();
int recv_sockfd;
int send_sockfd;
struct sockaddr_in servaddr;
std::thread recv_thread;
bool running;
};
#endif // UDPCOMM_HPP
udp_comm.cpp
#include "UdpComm.hpp"
#include <iostream>
#include <cstring>
#include <unistd.h>
#define BUFFER_SIZE 1024
UdpComm::UdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port) {
running = false;
// 수신 소켓 생성 및 바인드
if ((recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Receive socket creation failed" << std::endl;
throw std::runtime_error("Receive socket creation failed");
}
struct sockaddr_in recvaddr;
memset(&recvaddr, 0, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_addr.s_addr = inet_addr(local_ip.c_str());
recvaddr.sin_port = htons(local_port);
if (bind(recv_sockfd, (const struct sockaddr*)&recvaddr, sizeof(recvaddr)) < 0) {
std::cerr << "Receive bind failed: " << strerror(errno) << std::endl;
close(recv_sockfd);
throw std::runtime_error("Receive bind failed");
}
// 송신 소켓 생성
if ((send_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Send socket creation failed" << std::endl;
close(recv_sockfd);
throw std::runtime_error("Send socket creation failed");
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(remote_port);
servaddr.sin_addr.s_addr = inet_addr(remote_ip.c_str());
}
UdpComm::~UdpComm() {
stop();
close(recv_sockfd);
close(send_sockfd);
}
void UdpComm::start() {
running = true;
recv_thread = std::thread(&UdpComm::receive_udp, this);
}
void UdpComm::stop() {
running = false;
if (recv_thread.joinable()) {
recv_thread.join();
}
}
void UdpComm::send_data(const std::string& command, const std::string& data) {
std::string cmd = command;
cmd.resize(4, ' '); // Ensure command is 4 characters long
std::string message = cmd + data;
int n = sendto(send_sockfd, message.c_str(), message.size(), MSG_CONFIRM, (const struct sockaddr*)&servaddr, sizeof(servaddr));
if (n < 0) {
std::cerr << "sendto failed" << std::endl;
}
}
void UdpComm::receive_udp() {
char buffer[BUFFER_SIZE];
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
while (running) {
int n = recvfrom(recv_sockfd, buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&cliaddr, &len);
if (n < 0) {
if (running) {
std::cerr << "recvfrom failed" << std::endl;
}
continue;
}
buffer[n] = '\0';
std::string received(buffer);
std::string command = received.substr(0, 4);
std::string data = received.substr(4);
std::string sender_ip = inet_ntoa(cliaddr.sin_addr);
int sender_port = ntohs(cliaddr.sin_port);
on_receive(command, data, sender_ip, sender_port);
}
}
void UdpComm::on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) {
std::cout << "Received message: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
}
CustomUdpComm.hpp
#ifndef CUSTOMUDPCOMM_HPP
#define CUSTOMUDPCOMM_HPP
#include "UdpComm.hpp"
class CustomUdpComm : public UdpComm {
public:
CustomUdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port);
virtual ~CustomUdpComm();
protected:
void on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) override;
};
#endif // CUSTOMUDPCOMM_HPP
CustomUdpComm.cpp
#include "CustomUdpComm.hpp"
#include <iostream>
CustomUdpComm::CustomUdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port)
: UdpComm(local_ip, local_port, remote_ip, remote_port) {}
CustomUdpComm::~CustomUdpComm() {}
void CustomUdpComm::on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) {
std::cout << "Custom handler - Received message: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
}
main.cpp
#include "CustomUdpComm.hpp"
#include <iostream>
int main() {
std::string local_ip = "0.0.0.0"; // 모든 인터페이스에서 수신
int local_port = 5002;
std::string remote_ip = "C_PC_IP"; // C PC의 IP 주소로 설정
int remote_port = 5003;
try {
CustomUdpComm udp_comm(local_ip, local_port, remote_ip, remote_port);
udp_comm.start();
while (true) {
std::string command, data;
std::cout << "Enter command: ";
std::cin >> command;
std::cout << "Enter data: ";
std::cin >> data;
udp_comm.send_data(command, data);
}
udp_comm.stop();
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
Makefile
CXX = g++
CXXFLAGS = -std=c++11 -Wall
all: udp_comm
udp_comm: main.o UdpComm.o CustomUdpComm.o
$(CXX) $(CXXFLAGS) -o udp_comm main.o UdpComm.o CustomUdpComm.o
main.o: main.cpp CustomUdpComm.hpp
$(CXX) $(CXXFLAGS) -c main.cpp
UdpComm.o: UdpComm.cpp UdpComm.hpp
$(CXX) $(CXXFLAGS) -c UdpComm.cpp
CustomUdpComm.o: CustomUdpComm.cpp CustomUdpComm.hpp UdpComm.hpp
$(CXX) $(CXXFLAGS) -c CustomUdpComm.cpp
clean:
rm -f udp_comm main.o UdpComm.o CustomUdpComm.o
폴더 구조 변경 리펙토링
main.cpp는 CustomUdpComm 객체를 생성하고, 이를 사용하여 데이터 송수신을 수행합니다. daemon.cpp는 RT 스레드에서 주기적으로
데이터를 송신하는 함수를 포함하고 있습니다. main.cpp에서 pthread_create를 사용하여 RT 스레드를 생성하고,
daemon.cpp의 rt_thread_func 함수를 호출합니다
project/
├── include/
│ ├── UdpComm.hpp
│ └── CustomUdpComm.hpp
├── src/
│ ├── UdpComm.cpp
│ └── CustomUdpComm.cpp
├── daemon/
│ └── daemon.cpp
├── main.cpp
└── Makefile
UdpComm.hpp
#ifndef UDPCOMM_HPP
#define UDPCOMM_HPP
#include <string>
#include <thread>
#include <arpa/inet.h>
class UdpComm {
public:
UdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port);
virtual ~UdpComm();
void start();
void stop();
void send_data(const std::string& command, const std::string& data);
protected:
virtual void on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port);
private:
void receive_udp();
int recv_sockfd;
int send_sockfd;
struct sockaddr_in servaddr;
std::thread recv_thread;
bool running;
};
#endif // UDPCOMM_HPP
UdpComm.cpp
#include "UdpComm.hpp"
#include <iostream>
#include <cstring>
#include <unistd.h>
#define BUFFER_SIZE 1024
UdpComm::UdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port) {
running = false;
// 수신 소켓 생성 및 바인드
if ((recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Receive socket creation failed" << std::endl;
throw std::runtime_error("Receive socket creation failed");
}
struct sockaddr_in recvaddr;
memset(&recvaddr, 0, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_addr.s_addr = inet_addr(local_ip.c_str());
recvaddr.sin_port = htons(local_port);
if (bind(recv_sockfd, (const struct sockaddr*)&recvaddr, sizeof(recvaddr)) < 0) {
std::cerr << "Receive bind failed: " << strerror(errno) << std::endl;
close(recv_sockfd);
throw std::runtime_error("Receive bind failed");
}
// 송신 소켓 생성
if ((send_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cerr << "Send socket creation failed" << std::endl;
close(recv_sockfd);
throw std::runtime_error("Send socket creation failed");
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(remote_port);
servaddr.sin_addr.s_addr = inet_addr(remote_ip.c_str());
}
UdpComm::~UdpComm() {
stop();
close(recv_sockfd);
close(send_sockfd);
}
void UdpComm::start() {
running = true;
recv_thread = std::thread(&UdpComm::receive_udp, this);
}
void UdpComm::stop() {
running = false;
if (recv_thread.joinable()) {
recv_thread.join();
}
}
void UdpComm::send_data(const std::string& command, const std::string& data) {
std::string cmd = command;
cmd.resize(4, ' '); // Ensure command is 4 characters long
std::string message = cmd + data;
int n = sendto(send_sockfd, message.c_str(), message.size(), MSG_CONFIRM, (const struct sockaddr*)&servaddr, sizeof(servaddr));
if (n < 0) {
std::cerr << "sendto failed" << std::endl;
}
}
void UdpComm::receive_udp() {
char buffer[BUFFER_SIZE];
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
while (running) {
int n = recvfrom(recv_sockfd, buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&cliaddr, &len);
if (n < 0) {
if (running) {
std::cerr << "recvfrom failed" << std::endl;
}
continue;
}
buffer[n] = '\0';
std::string received(buffer);
std::string command = received.substr(0, 4);
std::string data = received.substr(4);
std::string sender_ip = inet_ntoa(cliaddr.sin_addr);
int sender_port = ntohs(cliaddr.sin_port);
on_receive(command, data, sender_ip, sender_port);
}
}
void UdpComm::on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) {
std::cout << "Received message: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
}
CustomUdpComm.hpp
#ifndef CUSTOMUDPCOMM_HPP
#define CUSTOMUDPCOMM_HPP
#include "UdpComm.hpp"
class CustomUdpComm : public UdpComm {
public:
CustomUdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port);
virtual ~CustomUdpComm();
protected:
void on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) override;
};
#endif // CUSTOMUDPCOMM_HPP
CustomUdpComm.cpp
#include "CustomUdpComm.hpp"
#include <iostream>
CustomUdpComm::CustomUdpComm(const std::string& local_ip, int local_port, const std::string& remote_ip, int remote_port)
: UdpComm(local_ip, local_port, remote_ip, remote_port) {}
CustomUdpComm::~CustomUdpComm() {}
void CustomUdpComm::on_receive(const std::string& command, const std::string& data, const std::string& sender_ip, int sender_port) {
std::cout << "Custom handler - Received message: Command: " << command << ", Data: " << data << " from " << sender_ip << ":" << sender_port << std::endl;
}
main.cpp
#include "CustomUdpComm.hpp"
#include <iostream>
#include <pthread.h>
CustomUdpComm* udp_comm_ptr = nullptr;
void* rt_thread_func(void* arg);
int main() {
std::string local_ip = "0.0.0.0"; // 모든 인터페이스에서 수신
int local_port = 5002;
std::string remote_ip = "C_PC_IP"; // C PC의 IP 주소로 설정
int remote_port = 5003;
try {
udp_comm_ptr = new CustomUdpComm(local_ip, local_port, remote_ip, remote_port);
udp_comm_ptr->start();
pthread_t rt_thread;
if (pthread_create(&rt_thread, NULL, rt_thread_func, NULL)) {
std::cerr << "Error creating RT thread" << std::endl;
return 1;
}
while (true) {
std::string command, data;
std::cout << "Enter command: ";
std::cin >> command;
std::cout << "Enter data: ";
std::cin >> data;
udp_comm_ptr->send_data(command, data);
}
udp_comm_ptr->stop();
delete udp_comm_ptr;
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
daemon.cpp
#include "../include/CustomUdpComm.hpp"
#include <iostream>
#include <unistd.h>
#include <pthread.h>
extern CustomUdpComm* udp_comm_ptr;
void* rt_thread_func(void* arg) {
while (true) {
// Example of sending data periodically
//udp_comm_ptr->send_data("PING", "Hello from RT thread");
// Sleep for 1 second
sleep(1);
}
return nullptr;
}
Makefile
CXX = g++
CXXFLAGS = -std=c++11 -Wall
INCLUDES = -I./include
SRC_DIR = ./src
OBJ_DIR = ./obj
DAEMON_DIR = ./daemon
all: udp_comm
udp_comm: $(OBJ_DIR)/main.o $(OBJ_DIR)/UdpComm.o $(OBJ_DIR)/CustomUdpComm.o $(OBJ_DIR)/daemon.o
$(CXX) $(CXXFLAGS) -o udp_comm $(OBJ_DIR)/main.o $(OBJ_DIR)/UdpComm.o $(OBJ_DIR)/CustomUdpComm.o $(OBJ_DIR)/daemon.o
$(OBJ_DIR)/main.o: $(SRC_DIR)/main.cpp include/CustomUdpComm.hpp include/UdpComm.hpp | $(OBJ_DIR)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/main.cpp -o $(OBJ_DIR)/main.o
$(OBJ_DIR)/UdpComm.o: $(SRC_DIR)/UdpComm.cpp include/UdpComm.hpp | $(OBJ_DIR)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/UdpComm.cpp -o $(OBJ_DIR)/UdpComm.o
$(OBJ_DIR)/CustomUdpComm.o: $(SRC_DIR)/CustomUdpComm.cpp include/CustomUdpComm.hpp include/UdpComm.hpp | $(OBJ_DIR)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/CustomUdpComm.cpp -o $(OBJ_DIR)/CustomUdpComm.o
$(OBJ_DIR)/daemon.o: $(DAEMON_DIR)/daemon.cpp include/CustomUdpComm.hpp include/UdpComm.hpp | $(OBJ_DIR)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $(DAEMON_DIR)/daemon.cpp -o $(OBJ_DIR)/daemon.o
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
clean:
rm -f udp_comm $(OBJ_DIR)/*.o
python side
udp_comm.py
import socket
import threading
class UdpComm:
def __init__(self, local_ip, local_port, remote_ip, remote_port):
self.local_ip = local_ip
self.local_port = local_port
self.remote_ip = remote_ip
self.remote_port = remote_port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((self.local_ip, self.local_port))
self.recv_thread = threading.Thread(target=self.receive_udp)
self.recv_thread.daemon = True
self.recv_thread.start()
def receive_udp(self):
while True:
data, addr = self.sock.recvfrom(1024) # 버퍼 크기 1024 바이트
self.on_receive(data.decode(), addr)
def send_data(self, command, data):
# Ensure command is 4 characters long
command = command.ljust(4)
message = command + data
self.sock.sendto(message.encode(), (self.remote_ip, self.remote_port))
def on_receive(self, message, addr):
command = message[:4]
data = message[4:]
print(f"Received message: Command: {command}, Data: {data} from {addr}")
# 위 코드를 udp_comm.py 파일로 저장해야 합니다.
main.py
from udp_comm import UdpComm # UdpComm 클래스가 정의된 파일명에 맞게 수정해야 합니다.
# IP 주소와 포트 설정
local_ip = "127.0.0.1" # 모든 인터페이스에서 수신
local_port = 5003
remote_ip = "127.0.0.1" # B PC의 IP 주소 (자기 자신)
remote_port = 5002
# UdpComm 인스턴스 생성
udp_comm = UdpComm(local_ip, local_port, remote_ip, remote_port)
# 사용자 입력을 통한 데이터 송신
while True:
command = input("Enter command: ")
data = input("Enter data: ")
udp_comm.send_data(command, data)
• main.py: UdpComm 클래스를 import하여 인스턴스를 생성하고, 사용자 입력을 받아 send_data 메서드를 통해 데이터를 송신합니다.
• udp_comm.py: UdpComm 클래스 정의 및 구현입니다. 생성자에서는 소켓을 바인딩하고, 별도의 쓰레드에서 데이터를 수신합니다. send_data 메서드는 입력받은 command와 data를 UDP로 전송하며, on_receive 메서드는 데이터를 수신하면서 콘솔에 출력합니다.
실행 방법
1. udp_comm.py 파일을 만들어 위의 코드를 저장합니다.
2. main.py 파일을 만들어 위의 코드를 저장합니다.
3. 각 PC의 IP 주소와 포트 번호를 자신의 환경에 맞게 수정합니다.
4. 먼저 udp_comm.py를 실행하여 UDP 통신을 대기시킵니다.
5. 그 다음 main.py를 실행하여 데이터를 입력하고 전송해보세요.
이렇게 하면 C++로 작성된 서버와 Python으로 작성된 클라이언트가 데이터를 주고받을 수 있습니다.
python call back 방식
main.py
from udp_client import UDPClient
def on_receive_callback(message, addr):
print(f"Received message from {addr}: {message}")
if __name__ == "__main__":
server_ip = '127.0.0.1'
receive_port = 5003
send_port = 5002
client = UDPClient(server_ip, receive_port, send_port)
client.set_receive_callback(on_receive_callback)
while True:
message = input("Enter message to send: ")
client.send_message(message)
udp_client.py
import socket
import threading
class UDPClient:
def __init__(self, server_ip, receive_port, send_port):
self.server_ip = server_ip
self.receive_port = receive_port
self.send_port = send_port
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.receive_callback = None
self.receive_thread = threading.Thread(target=self.receive_loop)
self.receive_thread.daemon = True
self.receive_thread.start()
self.client_socket.bind(('0.0.0.0', self.receive_port)) # 수신할 포트 설정
def set_receive_callback(self, callback):
self.receive_callback = callback
def receive_loop(self):
while True:
data, addr = self.client_socket.recvfrom(1024)
if self.receive_callback:
self.receive_callback(data.decode(), addr)
def send_message(self, message):
self.client_socket.sendto(message.encode(), (self.server_ip, self.send_port))
def close(self):
self.client_socket.close()
# 테스트용 예제
if __name__ == "__main__":
def on_receive_callback(message, addr):
print(f"Received message from {addr}: {message}")
server_ip = '127.0.0.1'
receive_port = 5003
send_port = 5002
client = UDPClient(server_ip, receive_port, send_port)
client.set_receive_callback(on_receive_callback)
while True:
message = input("Enter message to send: ")
client.send_message(message)
python call back 방식(보낼ip와 받는 ip가 다를때)
main.py
from udp_client import UDPClient
def on_receive_callback(command, data, addr):
print(f"Received message from {addr}: Command: {command}, Data: {data}")
if __name__ == "__main__":
local_ip = '127.0.0.1' # 수신할 IP
server_ip = '192.168.1.100' # 보낼 IP
receive_port = 5003 # 수신할 포트
send_port = 5002 # 보낼 포트
client = UDPClient(local_ip, server_ip, receive_port, send_port)
client.set_receive_callback(on_receive_callback)
while True:
command = input("Enter command (4 characters): ")
data = input("Enter data: ")
client.send_message(command, data)
udp_client.py
import socket
import threading
class UDPClient:
def __init__(self, local_ip, server_ip, receive_port, send_port):
self.local_ip = local_ip
self.server_ip = server_ip
self.receive_port = receive_port
self.send_port = send_port
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.receive_callback = None
self.receive_thread = threading.Thread(target=self.receive_loop)
self.receive_thread.daemon = True
self.receive_thread.start()
self.client_socket.bind((self.local_ip, self.receive_port)) # 수신할 포트 설정
def set_receive_callback(self, callback):
self.receive_callback = callback
def receive_loop(self):
while True:
data, addr = self.client_socket.recvfrom(1024)
if self.receive_callback:
command, data = self.parse_message(data.decode())
self.receive_callback(command, data, addr)
def send_message(self, command, data):
# Ensure command is exactly 4 characters long, trim if it's longer
if len(command) > 4:
print("Command is longer than 4 characters. Trimming to 4 characters.")
command = command[:4]
command = command.ljust(4)
message = command + data
self.client_socket.sendto(message.encode(), (self.server_ip, self.send_port))
def parse_message(self, message):
command = message[:4]
data = message[4:]
return command, data
def close(self):
self.client_socket.close()
# 테스트용 예제
if __name__ == "__main__":
def on_receive_callback(command, data, addr):
print(f"Received message from {addr}: Command: {command}, Data: {data}")
local_ip = '127.0.0.1' # 수신할 IP
server_ip = '127.0.0.1' # 보낼 IP
receive_port = 5003 # 수신할 포트
send_port = 5002 # 보낼 포트
client = UDPClient(local_ip, server_ip, receive_port, send_port)
client.set_receive_callback(on_receive_callback)
while True:
command = input("Enter command (up to 4 characters): ")
data = input("Enter data: ")
client.send_message(command, data)
windows에서 python error 발생 하는 이슈 대응 (option 추가해줘야 함)
oserror (10022 error).
소켓 옵션 설정: 윈도우에서 소켓을 재사용할 수 있도록 SO_REUSEADDR 옵션을 설정합니다.
import socket
import threading
class UDPClient:
def __init__(self, local_ip, server_ip, receive_port, send_port):
self.local_ip = local_ip
self.server_ip = server_ip
self.receive_port = receive_port
self.send_port = send_port
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 소켓 옵션 설정 (윈도우의 경우 필요할 수 있음)
self.client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
self.client_socket.bind((self.local_ip, self.receive_port))
print(f"Socket successfully bound to {self.local_ip}:{self.receive_port}")
except Exception as e:
print(f"Failed to bind socket to {self.local_ip}:{self.receive_port} - {e}")
self.receive_callback = None
self.recv_thread = threading.Thread(target=self.receive_udp)
self.recv_thread.daemon = True
self.recv_thread.start()
def set_receive_callback(self, callback):
self.receive_callback = callback
def receive_udp(self):
while True:
try:
print("Waiting to receive data...")
data, addr = self.client_socket.recvfrom(1024)
print("Data received!")
message = data.decode()
command = message[:4]
data = message[4:]
if self.receive_callback:
self.receive_callback(command, data, addr)
except Exception as e:
print(f"Error receiving data: {e}")
def send_message(self, command, data):
if len(command) > 4:
print("Warning: Command length is greater than 4 characters. Trimming command.")
command = command[:4]
message = command + data
try:
self.client_socket.sendto(message.encode(), (self.server_ip, self.send_port))
print(f"Sent message to {self.server_ip}:{self.send_port}")
except Exception as e:
print(f"Failed to send message to {self.server_ip}:{self.send_port} - {e}")
if __name__ == "__main__":
local_ip = '0.0.0.0' # 수신할 IP
server_ip = '192.168.1.41' # 보낼 IP
receive_port = 5300 # 수신할 포트
send_port = 5200 # 보낼 포트
client = UDPClient(local_ip, server_ip, receive_port, send_port)
def on_receive_callback(command, data, addr):
print(f"Received message from {addr}: Command: {command}, Data: {data}")
client.set_receive_callback(on_receive_callback)
while True:
command = input("Enter command (4 characters): ")
data = input("Enter data: ")
client.send_message(command, data)