본문 바로가기
프로그래밍 언어/Python

[Python] TCP/IP 소켓 통신 (Server/Client)

by mssil-7 2024. 7. 24.

TCP/IP 통신을 하기 위해 소켓(Socket)을 이용합니다. 소켓은 각 포트를 사용하여 통신을 수행하는 도구로 각 프로그램에 포트를 세팅하고 소켓으로 데이터를 주고 받습니다. 즉, 포트는 출입구라하면 소켓은 데이터를 직접 송수신하는 매체가 됩니다. 

 

import socket

 

* PyQt를 통해 UI를 구성했기 때문에 QThread를 사용했습니다. UI 연동 없이 테스트 한다면 QThread 대신에 Thread 쓰시면 됩니다.

 

1. Server Socket

 

servet socket의 역할은 client socket의 연결 요청을 대기하고, 연결 요청이 오면 클라이언트 소켓을 생성하여 통신을 가능하게 합니다.

 

serverSample.py

class Server():
    def __init__(self):
        super().__init__()
        self.server_socket: socket
        
    # ConnectionRefusedError
    def Connect(self, ip, port):
        try:
            ADDR = (ip, int(port))
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
            self.server_socket.bind(ADDR)
            self.server_socket.listen()
            return True
        except:
            return False
            

    def Disconnect(self):
        self.server_socket.close()


class ServerRecvThread(QThread):
    connect = pyqtSignal(str)
    recvData = pyqtSignal(str)
    
    def __init__(self, server):
        super().__init__()
        self.server_socket = server
        self.recvThread: RecvThread

    def run(self):
        try:
            while True:
                # 클라이언트 연결 대기
                self.client_socket, client_address = self.server_socket.accept()
                # self.connect.emit(client_address[0])
                
                recvThread = RecvThread(self.client_socket)
                recvThread.start()
                recvThread.recvData.connect(self.GetRecv) 
        except:
            pass       
    
    @pyqtSlot(str)
    def GetRecv(self, recv):
        self.recvData.emit(recv)
                    
    
    def stop(self):
        self.client_socket.close();
        self.quit()
        

        
class RecvThread(QThread):
    recvData = pyqtSignal(str)
    
    def __init__(self, client):
        super().__init__()
        self.client_socket = client
        

    def run(self):
        try:
            while True:
                time.sleep(1)
                recv_data = self.client_socket.recv(1024).decode()  # 클라이언트가 보낸 메시지 반환
                if recv_data != "":
                    self.recvData.emit(recv_data)
        except:
            pass

    def stop(self):
        self.quit()
    


class ServerSendThread(QThread):
    connect = pyqtSignal(str)
    
    def __init__(self, server):
        super().__init__()
        self.server_socket = server
        self.client_socket: socket
        self.sendThread: SendThread
        self.ip = None

    def run(self):
        # try:
            while True:
                self.client_socket, client_address = self.server_socket.accept()
                if self.ip == None or self.ip != client_address[0]:
                    self.connect.emit(client_address[0])
                    self.ip = client_address[0]
                                    
                self.sendThread = SendThread(self.client_socket)
                self.sendThread.start()
        
        # except Exception as e:
        #     print("error: " + str(e))
        #     pass

    def send(self, msg):
        self.client_socket.send(msg.encode())  # 클라이언트에게 응답
        
        
    def stop(self):
        self.quit()
        self.wait(5000)
        
        
class SendThread(QThread):
    recvData = pyqtSignal(str)
    
    def __init__(self, client):
        super().__init__()
        self.client_socket = client


    def send(self, msg):
        self.client_socket.send(msg.encode())
        

    def stop(self):
        self.quit()

 

main.py 

import serverSample
def Connect():
    	server = serverSample.Server()
        status = server.Connect(IP, Port)

        if status:
            server_Thread = serverSample.ServerSendThread(server.server_socket)
            server_Send_Thread.start()
            server_Recv_Thread.recvData.connect(self.RecvResult)
           
        else:
            print("Connect Failed")

 

2. Client Socket

 

client socket은 대기 없이 바로 사용 가능하며, 실제로 데이터 송수신이 일어나는 곳입니다. 

 

clientSample.py

class Client():    
    def __init__(self):
        super().__init__()
        
    def Send(self, msg):
        self.client_socket.send(bytes(msg.encode())) 

            
    def Connect(self, ip, port): 
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            ADDR = (ip, int(port))
            self.client_socket.connect(ADDR)
            return True
        except :
            return False


    def Disconnect(self):
        self.client_socket.close();
        
            
class ClientThread(QThread):
    recvData = pyqtSignal(str)
    
    def __init__(self, client):
        super().__init__()
        self.client_socket = client
        
    def run(self):
        try:
            while True:
                time.sleep(1)
                recv_data = self.client_socket.recv(1024).decode()
                self.recvData.emit(recv_data)
        except:
            pass

    def stop(self):
        self.quit()

 

main.py

import clientSample
def Connect():
    client = clientSample.Client()
    status = client.Connect(IP, Port)

    if status:
        client_Thread = clientSample.ClientThread(client.client_socket)
        client_Thread.start()
        client_Thread.recvData.connect(RecvResult)
    else:
        self.consoleAppend("connect failed")

@pyqtSlot()
def RecvResult(recv):
    print("\r\nRecvResult : " + recv)