소켓 프로그래밍

한결·2021년 7월 28일
0

이것저것

목록 보기
1/4
post-thumbnail

공개 SW개발대회를 준비하면서 소켓프로그래밍을 공부하다가 정리가 굉장히 잘되어있는 글을 발견했습니다.

게시글 링크

제가 작성하는 글은 위 블로그의 게시글을 다시한번 정리한 글입니다


소켓 프로그래밍을 하는데 있어서 Server와 클라이언트가 필요하다
포트포워딩까지 하지는 않고 로컬호스트에서 두개의 터미널을 통해 테스트를 해보겠습니다.

#server.py
from socket import * #소켓 모듈을 가져온다

server = socket(AF_INET, SOCK_STREAM) #socket() 함수를 사용하여 소켓생성
server.bind(('', 8080)) #포트에 바인딩한다
server.listen(1) #접속할 클라이언트 수를 설정한다

connectionSock, addr = server.accept()
client.py
from socket import *

client = socket(AF_INET, SOCK_STREAM) #소켓생성
client.connect(('127.0.0.1', 8080)) #생성한 소켓을 통해 로컬호스트:8080에 접속

상대방이 접속하면 accept()가 실행되고 return 값으로 새로운 소켓과, 상대방의 AF(Address Family)를 전달해주게 되면서 프로그램이 종료됩니다.


다음은 소켓을 통해 메시지를 전달하고 받는 방법을 알아보겠습니다.
받고, 보내는 방법은 send()와 recv() 메서드를 사용하여 간편하게 구현할 수 있습니다.

#server.py
from socket import * #소켓 모듈을 가져온다

server = socket(AF_INET, SOCK_STREAM) #socket() 함수를 사용하여 소켓생성
server.bind(('', 8080)) #포트에 바인딩한다
server.listen(1) #접속할 클라이언트 수를 설정한다

connectionSock, addr = server.accept()

data = connectionSock.recv(1024)
print('상대방: ', data.decode('utf-8'))

connectionSock.send('저는 서버입니다'.encode('utf-8'))
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8080))

clientSock.send('저는 클라이언트입니다'.encode('utf-8'))

data = clientSock.recv(1024)
print('상대방: ',data.decode('utf-8'))

추가로 확인해야할 부분이 있는데 send로 보낼때 utf-8로 인코딩, recv로 받을때 디코딩 해주어야합니다.
결과는 서버에서는 클라이언트의 메시지를받고, 클라이언트는 서버에서 메시지를 받으며 프로그램이 종료됩니다.
다음은 사용자의 입력을 받아 지속적으로 메시지를 전송해보겠습니다.

#server.py
from socket import * #소켓 모듈을 가져온다

server = socket(AF_INET, SOCK_STREAM) #socket() 함수를 사용하여 소켓생성
server.bind(('', 8080)) #포트에 바인딩한다
server.listen(1) #접속할 클라이언트 수를 설정한다

connectionSock, addr = server.accept()

while True:
    sendData = input('입력: ')
    connectionSock.send(sendData.encode('utf-8'))

    recvData = connectionSock.recv(1024)
    print('상대방: ', recvData.decode('utf-8'))
from socket import *

clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8080))

while True:
    recvData = clientSock.recv(1024)
    print('상대방: ', recvData.decode('utf-8'))

    sendData = input('입력: ')
    clientSock.send(sendData.encode('utf-8'))

성공적으로 메시지를 주고받게 되었습니다.
다만 위의 코드에서도 보이는 문제점이 있는데 바로 한쪽은 먼저받고 후에 보내고, 다른한쪽은 먼저보내고 후에 받고 와 같은 방식으로 소통하고있습니다.

이러한 문제를 해결하기위한 방법이 스레드입니다.

스레드(thread)는 어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다.
일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드(multithread)라고 한다.위키백과

그렇습니다. 멀티스레드를 통해서 두개의 스레드 즉, recv와 send를 동시에 실행시킬것입니다.

파이썬에서 스레드를 생성하는 방법은 다음과 같습니다.

threading.Thread(target=함수, args=(함수인자,))

그러면 학습한 스레드의 개념을 토대로 프로그램을 작성해보겠습니다.

#server.py
from socket import *
import threading
import time


def send(sock):
    while True:
        sendData = input('>>>')
        sock.send(sendData.encode('utf-8'))


def receive(sock):
    while True:
        recvData = sock.recv(1024)
        print('상대방 :', recvData.decode('utf-8'))

server = socket(AF_INET, SOCK_STREAM)
server.bind(('', 8080))
server.listen(1)

connectionSock, addr = server.accept()

sender = threading.Thread(target=send, args=(connectionSock,))
receiver = threading.Thread(target=receive, args=(connectionSock,))

sender.start()
receiver.start()

while True:
    time.sleep(1)
    pass
#server.py
from socket import *
import threading
import time


def send(sock):
    while True:
        sendData = input('>>>')
        sock.send(sendData.encode('utf-8'))


def receive(sock):
    while True:
        recvData = sock.recv(1024)
        print('상대방 :', recvData.decode('utf-8'))

server = socket(AF_INET, SOCK_STREAM)
server.bind(('', 8080))
server.listen(1)

connectionSock, addr = server.accept()

sender = threading.Thread(target=send, args=(connectionSock,))
receiver = threading.Thread(target=receive, args=(connectionSock,))

sender.start()
receiver.start()

while True:
    time.sleep(1)
    pass

이전 코드와 다른점은 스레드생성시 함수를 넣어줘야하기에 send와 recv를 함수의 형태로 만들었습니다.
또한 작성한 스레드를 .start()를 통해서 실질적으로 실행시켜주었습니다.

맨 아래 작성한 코드의 의미는 스레드는 프로세스가 종료되면 사라지므로 프로세스또한 계속해서 실행될 수 있도록 루프를 돌려주었습니다.

완성된 코드를 실행시키면 recv와 send 스레드가 동시에 실행되며 정상적으로 작동되는 모습을 볼 수 있습니다.

profile
개발

0개의 댓글