파이썬 TCP 소켓 프로그래밍 - 메세지 송수신

이전에 C언어 소켓 프로그래밍에 관한 수업을 들은 적이 있는데 자세한 내용은 다루지 못하고 급하게 넘어갔던 기억이 있는데 요즘에 파이썬에 꽂혀있어서 파이썬으로 소켓 프로그래밍에 대해서 다시 한번 이해하고 정리하기 위해 글을 작성합니다

 

소켓 모듈 가져오기

1
from socket import *
cs

 

소켓 프로그래밍을 위해 서버와 클라이언트 최상단에 socket 모듈을 불러와주세요

 

서버(Server) 소켓 설정

1
2
3
4
5
6
7
= socket(AF_INET,SOCK_STREAM)
print('socket 생성')
 
s.bind(("localhost",7777))
s.listen(5)
 
print('서버가 연결을 기다리고 있습니다.')
cs

 

#1

우선 socket 객체를 생성하고 저는 s라고 변수를 선언해주었습니다

socket함수를 사용할때에는 두 가지 인자를 입력해야 하는데 각각에 해당되는 주소체계(AdressFamily)와 소켓 타입(SocketTtype)을 입력해줘야 합니다

코딩할 때 찾아보니깐 IPv4 주소체계의 경우 AF_INET을 사용하고 IPv6 주소체계의 경우 AF_INET6을 사용한다고 합니다
아직까지는 IPv4 주소체계를 많이 사용하니깐 웬만해선 IPv4를 사용하지만 개념만 알고 넘어가면 될 거 같습니다

소켓 타입의 경우 TCP 통신은 SOCK_STREAM을 사용하고 UDP타입의 경우에는 SOCK_DGRAM을 사용한다 정도만 알아두면 될 거 같습니다 이번 게시물에서 사용할 소켓 타입은 TCP타입인 SOCK_STREAM입니다 
소켓 타입에는 CLOEXEC, DGRAM, NONBLOCK, RAW, RDM, SEQPACKET, STREAM 등이 있습니다

 

#2

편의상 터미널에 socket객체가 생성되었다고 과정을 print문으로 출력해주도록 합니다


#4

소켓을 생성한뒤에는 bind함수를 사용하여 호스트와 포트번호를 튜플로 감싸서 전달하며 소켓에 주소 정보를 할당합니다.

bind() 함수의 첫번째값은 호스트 주소와 두 번째 값은 포트를 의미합니다

지금은 동일 컴퓨터내에서 공부를 목적으로 내부 간의 통신을 위해 호스트는 localhost를 사용합니다

 

#5

listen()함수는 클라이언트의 요청을 대기하는 함수이며 본문에 있는 코드에 listen(5) 중에 정수 5는 큐의 공간을 의미하며 이는 최대 5개까지의 클라이언트 연결 요청을 대기할 수 있다는 의미입니다

 

#7

listen()함수가 정상적으로 수행된 후에 서버가 연결을 기다리고 있다고 print문으로 작성하여 프로그램 실행 시 터미널에 출력해줍니다

 

TCP와 UDP

TCP는 연결형 서비스로 UDP에 비해 높은 신뢰성을 보장하며 데이터흐름이 연속적입니다 또 서버는 클라이언트와 1:1로 연결되어 STREAM전송으로 전송 데이터의 크기에 대한 제한이 없습니다 주로 HTTP 등에서 많이 사용됩니다


UDP는 비연결형 서비스로 패킷을 전송하면 수신자가 패킷을 전달받았는지에 대한 유무를 알수가 없다 그래서 TCP에 비해 신뢰성은 낮고 속도는 빠르며 UDP서버는 1:1, 1:N, N:1, N:N 관계로 연결될 수도 있다 클라이언트와 서버 간의 연결이 없어 소켓의 구분이 따로 없습니다

 

 

TCP 와 UDP 차이를 자세히 알아보자

TCP와 UDP는 TCP/IP의 전송계층에서 사용되는 프로토콜이다. 전송계층은 IP에 의해 전달되는 패킷의 오류를 검사하고 재전송 요구 등의 제어를 담당하는 계층이다.

velog.io

 

 

위 블로그에 들어가게되면 TCP와 UDP에 대한 자세한 설명과 그림으로 직관적으로 볼 수 있게 잘 정리되어있습니다
TCP와 UDP에 관해 조금더 자세히 공부하고 싶다면 추천해드립니다

 

 

서버(Server) 소켓 송수신

소켓 송수신시에 중요한 함수는 send와 recv입니다

이름에서 알수있듯이 전송 시에 sned함수를 사용하고 수신 시에 recv함수를 사용하면 됩니다

 

1
2
3
4
5
6
7
while True:
    csock,addr = s.accept()
    
   stext = csock.recv(512).decode()
    print('메세지:',addr,stext)
 
    csock.send(bytes('메세지가 성공적으로 전송되었습니다','utf-8')
cs

 

#2

2번째 줄에 csock과 addr가 있는데 각각 클라이언트 소켓과 ip주소를 뜻합니다

accept() 함수는 소켓에 누군가가 접속하였을 시에 새로운 소켓을 return 하여 클라이언트와 통신 시에 사용합니다

 

서버에 접속한 상대방과 데이터를 송수신하기 위해서는 accpet() 함수를 통해 생성된 csock을 사용함(csock의 이름은 임의로 지었습니다)

 

#4

stext이라는 변수에는 2번째 줄에서 선언한 csock함수 즉 클라이언트에서 전송하여 16비트로 인코딩 된 내용을 디코딩하여 문자열로 변환합니다 'stext'라는 변수는 클라이언트 측의 변수랑 이름이 반드시 동일할 필요는 없습니다

소켓에서 문자열을 전송/수신하기 위해서는 인코딩/디코딩 과정이 필요합니다

이 과정을 생략하고 사용 시에는 에러가 발생하게 됩니다

이때 recv()의 인자 값 512는 bytes라고 생각하시면 됩니다 최대 512 bytes까지의 내용을 읽어올 수 있습니다

 

#5

addr = server 측 터미널에 사용자의 주소

stext = 4번째 줄에 디코딩한 클라이언트 측의 평문 문자열을 출력해줍니다

 

#7

sned() 함수를 통하여 전송할 문자열을 bytes()에 담은 후에 바이트형으로 인코딩하여 클라이언트 측으로 전송합니다

즉 #7번부분 코드는 클라이언트가 보낸 메시지를 수신하여 출력한뒤 메세지를 성공적으로 받았다고 다시 서버에서 클라이언트 측으로 문자열을 전송하는 부분입니다

 

#1

통신을 지속적으로 유지하기 위해 이 과정을 while로 무한반복해줍니다

 

클라이언트 소켓 설정

1
2
3
4
5
6
7
8
9
10
11
from socket import *
 
while True:
    csock = socket(AF_INET,SOCK_STREAM)
    csock.connect(("localhost",7777))
 
    text = input('>>')
    if len(text) < 1:
        text = ' '
    csock.send(bytes(text, 'utf-8'))
    print(csock.recv(512).decode())
cs

 

#4

서버 쪽과 비슷하게 이번엔 클라이언트 쪽에서 소켓을 생성합니다

서버쪽 함수와 클라이언트 측 함수를 구분을 위해 서버쪽 소켓은 s 클라이언트쪽 소켓은 csock으로 구분하였습니다

socket() 함수에 대해서는 서버 쪽에서 설명을 하였기때문에 넘어가겠습니다

 

#5

앞서 서버에서는 bind함수로 요청을 기다리는 상황이고 클라이언트에서 서버 연결 시에는 connect() 함수를 사용합니다

connect() 함수 안에는 연결할 호스트 주소와 포트번호를 인자 값에 넣어줍니다

 

#7

사용자로부터 문자열을 입력받아 받아오는 과정입니다 

입력받은 문자열은 text변수에 넣어줍니다

 

#8~#9

if문을 사용하여 text에 입력된 문자열의 길이가 0 이하인지를 확인합니다

 

0 이상 즉 사용자로부터 입력받은 문자열의 길이가 1 이상일 경우에는 #10줄로 넘어가게 되고 그렇지 않은 경우에는 text에 공백 문자열을 추가해줍니다

 

이렇게 하는 이유는 client 사용자가 빈 메시지를 입력하여 엔터를 누르면 client사용자는 빈 문자열로 send() 함수를 호출할때 client가 server에는 빈 패킷을 전송하는게 아니라 아무런 패킷도 전송하지 않습니다

그리고 이 과정에서 오류가 발생하게 되는데 이를 방지하기 위해서 사용자로부터 입력된 내용이 있는지 없는지 확인 후에 입력된 내용이 없다면 text변수에는 공백을 추가하여 #10 단계에서 bytes로 인코딩 후에 최종적으로 20이라는 bytes데이터를 전송하게 됩니다

 

' '공백 문자는 bytes로 변환 시에 20이라는 bytes값이 나옵니다

아래 사이트는 문자열을 bytes로 변환시에 나오는 값을 확인할 수 있습니다

 

 

Convert UTF8 to Bytes - Online UTF8 Tools

World's simplest online utility that converts UTF8 text to bytes. Free, quick, and powerful. Import UTF8 – get bytes.

onlineutf8tools.com

 

#10

수신 시에는 recv를 사용하고 전송 시에는 send 함수를 사용합니다

sned() 함수 안에 아까 사용자로부터 입력받은 내용이 저장된 text변수를 전송하면 되는데 문자열로 전송 시에는 오류가 발생하므로 이를 utf-8로 인코딩하여 16진수 데이터로 변환하여 보냅니다

 

#11

server 쪽에서 csock.send로 전송한 메시지가 성공적으로 전송되었다는 문자열을 받아 온 후 인코딩 된 16진수 HEX값을 디코딩하여 터미널에 문자열을 출력합니다

recv() 함수의 인자 값은 서버 소켓에서 설명했듯이 512 bytes의 내용을 읽어올 수 있습니다

 

 

실행 결과

 

서버 실행

Server측 실행결과

server을 실행시킨 후 정상적으로 소켓을 생성하면 소켓 생성 메시지와 listen() 함수까지 수행되었을 경우에 서버가 연결을 기다리고 있다는 준비상태 메시지가 터미널에 표시됩니다

 

클라이언트 실행

client측 실행결과

client을 실행한 후에 >>가 터미널에 표시되고 input() 함수를 통해 사용자로부터의 데이터 입력을 기다리고 있는 걸 확인할 수 있습니다

 

 

 

 

 

클라이언트 메시지 전송 결과

 

메세지 전송후 clinet측 결과

hello라는 문자열을 입력 후에 전송할 경우 메시지가 성공적으로 전송되었다는 내용이 출력됩니다

 

 

 

클라이언트 메세지 수신 결과

메세지를 수신받은 server측 결과

clinet에서 메시지를 send()함수로 전송한 이후에 server측에서는 recv함수로 메세지를 받아온후 decode로 내용일 디코딩하여 입력받은 메세지를 터미널에 출력해줍니다

 

 

 

만약에 공백을 입력하였을 경우에는

 

좌 서버 우 클라이언트

server에서 문자열을 입력하지 않고 전송하였을 경우에 if문 처리로 인해 공백의 문자열이 전송되어 클라이언트에는 공백으로 사용자의 메시지가 출력됩니다

 

 

참고자료

 

 

#파이썬. 파이썬 소켓(socket) 프로그래밍

파이썬 소켓(socket) 프로그래밍네트워크 프로그래밍을 위하여 소켓(socket)을 통해 서버와 클라이언트간 ...

blog.naver.com

 

 

파이썬 소켓 프로그래밍 - 1. 간단한 채팅 프로그램 구현(1)

작년에 컴퓨터 네트워크 강의시간에 파이썬 소켓 프로그래밍 강의를 받은 적이 있습니다. 간단한 웹 서버 구축과 채팅 프로그램 구축 둘 중 하나를 택하는 거였는데, 네트워크 개념을 다시 복습

seolin.tistory.com

 

Python client hanging when sending empty message to server

I have a python reverse shell that I am working on that utilizes a client-server connection using TCP. I am testing them both right now on my localhost windows machine and I am utilizing the subpro...

stackoverflow.com

 

 

How to prevent python socket server from sending blank message? : Forums : PythonAnywhere

this works fine (have added: import socket to top line of server.py) - if users behave correctly but if one person hits return at the wrong time, or tries sending two message then the whole thing just hangs So I want to fix that and then somehow add it to

www.pythonanywhere.com

 

 

파이썬 소켓 연결 사용법 · Wireframe

네트워크 프로그래밍 분야에서 소켓은 연결된 네트워크의 양 끝단을 추상화 시킨 개념이며, 컴퓨터의 관점에서는 네트워크로 통하는 컴퓨터의 외부와 컴퓨터 내부의 프로그램을 이어주는 인터

soooprmx.com

 

 

파이썬 소켓 프로그래밍 - 클라이언트 / 서버 예제

파이썬에서 소켓을 사용한 TCP 서버/클라이언트 예제에 대해 다룹니다. 클라이언트가 서버에 접속하여 통신이 시작되는 방식입니다.  1. TCP 소켓      2. 간단한 에코 서버, 클라이언트 예제  

webnautes.tistory.com

 

 

GITHUB

 

GitHub - Blue-B/python-TCP-socket----01

Contribute to Blue-B/python-TCP-socket----01 development by creating an account on GitHub.

github.com

 

Top