상세 컨텐츠

본문 제목

14. 소켓(Socket)

Python

by evaseo 2021. 5. 1. 15:02

본문

1.    소켓

(1)     네트워크 상에서 돌아가는 두 개의 프로그램 간 양방향 통신의 하나의 엔드 포인트

(2)     포트 번호에 바인딩되어 TCP레이어에서 데이터가 전달되어야 하는 어플리케이션을 식별할 수 있게 한다.

(3)     소프트웨어로 작성된 통신 접속점

(4)     TCP/IP 프로토콜을 기반으로 네트워크 응용 프로그램은 소켓을 통하여 네트워크 통신망으로 데이터를 송수신

(5)     소켓은 프로세스 간에 대화가 가능하도록 하는 통신방식으로 클라이언트와 서버 모델에 기초

(6)     순서 상 먼저 서버 프로세스를 위한 server socket 객체 생성

(7)     서버 서비스가 원활하게 진행된다면 다음으로 클라이언트 프로세스를 생성

(8)     같은 ip port 번호를 가진 서버와 클라이언트는 소켓을 통한 양방향 통신이 가능

(9)     소켓은 전화기의 잭에 해당하는 역할을 하므로, 네트워크를 사용하는 통신을 하기 전에 클라이언트와 서버 양측 모두에 소켓 객체를 만들어 두어야 한다.

 

2.    엔드 포인트

(1)     아이피 주소와 포트번호의 조합을 의미

(2)     모든 TCP연결은 2개의 엔드 포인트로 유일하게 식별

(3)     따라서 클라이언트와 서버 간 여러 개의 연결이 맺어질 수도 있다.

 

3.    TCP(연결지향 Socket)

(1)     통신을 시작하기 전에 연결작업이 되어 있어야 하는 통신규약

(2)     이런 유형을 가상회선 또는 Stream Socket이라 한다.

(3)     송신 측에서 보낸 내용이 수신 측에서 정확하게 자료를 전달받았을 때 신뢰성이 유지

(4)     UDP에 비해 속도는 느림

(5)     소켓에 주소정보를 bind() 함수로 묶어서 지속적인 데이터 송수신 가능

(6)     인터넷, 전화

ex) A B 에게 ‘hello’라는 메시지를 보냈다고 가정할 경우,
정확히 B 에게 ‘hello’라는 내용을 전달해야 한다.
중간에 오류로 알 수 없는 메시지가 전달되면 신뢰성이 없는 통신이 되는 것


4.    UDP (비연결형 Socket)

(1)     통신 처리할 때 연결작업이 필요 없는 통신규약

(2)     자료 전달을 할 경우 순서, 중복 방지, 신뢰성을 보장받을 수 없으며, 데이터가 연결되어 있지 않다.

(3)     소켓에 데이터를 보낼 때 마다 주소정보를 같이 할당

(4)     사실은 연결할 수는 있지만 기본적으로는 연결이 안되는 것이 일반적

(5)     UDP TCP에 비해 속도가 빠름 -> 실시간 스트리밍 방식으로 사용하기에 적합

(6)     TV(송신만 계속함)

  ex) A B에게 메시지들을 전달해야 할 경우, 수신하는 B측의 수신여부는 상관하지 않고, 일방적으로 메시지를 전달하는 경우


5.    TCP/IP 프로토콜 기반 소켓 실행 흐름


6.    import socket / from socket import * 로 로딩 필요

 

7.    함수 import socket

(1)     socket.getservbyname(확인할 서버,'tcp'): 서버의 port번호 확인

(2)     socket.getaddrinfo('domain name', port, proto=socket.SOL_TCP)

1)       proto는소켓 프로토콜 정보를 나타내는 속성이며, socket.SOL_TCP는 소켓옵션 중 하나를 의미

2)       사이트의 소켓의 종류와 ip 주소를 확인할 수 있다.

#Socket: TCP/IP protocol(통신규약)의 프로그래머 인터페이스를 파이썬은 모듈로 지원

import socket

print(socket.getservbyname('http','tcp')) #80
print(socket.getservbyname('telnet','tcp')) #23
print(socket.getservbyname('ftp','tcp')) #21 ex)파일질라
print(socket.getservbyname('smtp','tcp')) #25
print(socket.getservbyname('pop3','tcp')) #110 이메일
print()

#소켓을 이용해서 해당 사이트의 정보를 얻을 수 있다.
print(socket.getaddrinfo('www.naver.com', 80, proto = socket.SOL_TCP))
print(socket.getaddrinfo('www.daum.net', 80, proto = socket.SOL_TCP))​
실행결과

8.    통신 함수

(1)     공통

1)       socket.socket(socket_family, socket_type, [protocol=0]) / socket(socket.socket_family, socket.socket_type, [protocol=0])

        첫 번째 인자로 Address Family(AF) Socket Type(Enum형태의 Int)을 받는다.

        socket() 함수 인자 Address Family Socket Type의 기본값은 각각 AF_INET, SOCKET_STREAM

        socket_family: AF_UNIX (file-based), AF_INET (network-oriented)

i.     AF_INET (Address Family Internet)

a.       인터넷을 이용한 통신

b.      가장 일반적으로 사용되며, 서버와 클라이언트가 서로 떨어져 독립적으로 있을 수도 있다.

ii.    AF_UNIX(Address Family Unix)

a.       서버와 클라이언트가 같은 컴퓨터에 존재

b.      유닉스용 소켓

        socket_type: SOCK_STREAM (tcp), SOCK_DGRAM (udp)

i.     SOCK_STREAM

a.       스트림 연결(TCP)

b.      신뢰성이 좋다.

c.       전송할 수 있는 크기가 가변적이다.

ii.    SOCK_DGRAM

a.       데이터그램 연결(UDP) 유형

b.      신뢰성이 떨어지나 속도는 빠름

        protocol: 기본값은 0으로 보통은 생략한다.
ex) ss=socket(AF_INET, SOCK_STREAM)

 

     소켓주소 자료구조

n  Family: 사용될 프로토콜군을 식별하는 16 비트 정수 값

n  Port Number: 프로세스에 할당된 포트번호를 식별하는 16 비트 정수 값

n  주소: 프로세스가 실행되는 호스트의 인터넷 주소를 포함하는32 비트 정수 값


2)       send(byte), sendall(byte) - 데이터 송신

        클라이언트 소켓에서 서버 소켓으로 데이터 전송

        send()

i.     low-level에서 작동되는 시스템콜 형태

ii.    sendall()과는 달리 실제 전송된 바이트 수를 반환

iii.   보내려는 데이터와 실제 보내진 데이터가 다를 수 있다는 의미

iv.   보내지 못한 데이터를 보낼 책임은 프로그래머에게 있다.

        sendall()

i.     high-level단의 메소드로 python 메소드

ii.    요청한 데이터의 모든 버퍼 내용을 모두 전송. 그렇지 않으면 Exception발생

iii.   sendall()도 내부적으로는 send()를 이용하는데 단지 모두 전송할 때까지 send()를 호출한다.

        바이트 시퀀스로 전송

        만약 문자열을 주고받고 싶다면 해당 문자열을 인코딩/디코딩해서 전달

3)       recv(bufsize) - 데이터 수신

        데이터를 수신

        수신한 데이터(바이트 객체)를 반환한다.

        bufsize는 한 번에 수신할 수 있는 최대 데이터 크기를 의미, 단위는 byte

        읽어 들인 데이터는 bytes 타입의 바이트 시퀀스

4)       close() - 연결 요청 대기 종료

 

(2)     서버

1)       서버 소켓

        서버 소켓은 대기 소켓(수신 소켓)과 실제 통신을 담당하는 소켓(응답 소켓 또는 반환 소켓)으로 설정

        서버 소켓은 연결 요청을 대기하다가 연결을 수락하는 경우 새로운 Socket 객체를 반환한다.

        실제 외부와의 통신은 여기서 반환된 새로운 Socket객체를 통해 통신한다.

2)       bind((HOST, PORT)) - 소켓 맵핑

        생성한 소켓에 고유한 호스트와 포트를 매핑한다.

        인자로 address(호스트와 포트 정보)를 튜플 형태로 전달받는다.
ex) socket.bind(HOST, PORT)

        Socket 객체(프로그램 인터페이스)에 고유한 네트워크 IP자원(호스트와 포트)를 맵핑함으로써 프로그램 인터페이스와 네트워크 지원을 연결시킨다.

        HOST ip를 지정하지 않으면 가능한 모든 인터페이스를 의미

     PORT: 하나의 컴퓨터에 실행 중인 여러 네트워크 프로그램을 구분하기 위해 부여된 번호

n  포트번호는 0 ~ 65535 번 까지를 사용가능

n  well-known port: 0- 1024

n  보통 새로운 서버를 만든다면 well-known port는 가급적 피하는 것이 좋다.

3)       listen(클라이언트 동시 접속 수(1 ~ 5)) - 연결 요청 대기 상태 설정

        소켓은 생성된 이후 연결 요청 대기를 한 이후에만 연결이 가능하므로 소켓 맵핑 후에는 반드시 연결 요청 대기 상태를 설정해야 한다.

        연결 대기 상태는 오로지 대기(listen)만 한다.

        TCP를 사용하는 연결-지향 응용 프로토콜에서의 서버 프로세스가 연결을 받아들이겠다는 것을 나타내기 위한 호출

4)       accept() - 연결 승낙 후 실제 통신 소켓 반환

        연결을 승낙하고 연결이 성립된 새로운 소켓과 주소정보를 반환한다.

        실제 외부와의 통신은 여기서 생성된 새로운 소켓을 이용한다.

        시스템에 의해서 반응이 주어짐 - callback함수

 

(3)     클라이언트

1)       클라이언트 소켓: 서버 소켓과 달리 오로지 클라이언트 소켓 하나로 구성

2)       connect((HOST, PORT)) - 서버 소켓에 연결 요청

        서버 소켓에 연결 요청

        인자로 address(연결할 소켓의 호스트와 포트 정보)를 튜플 형태로 전달받는다.

        파이썬 3.5버전 이후에는 연결이 종료된 경우 InterruptedError에러나 socket.timeout 없이 대기 상태로 전환된다.

 

예제1) 클라이언트의 요청에 대해 1회만 반응하는 서버

<서버실행 시 서버 출력 결과>

<soc1_server>
#접속상태 확인을 위한 단순 에코(echo-메아리)서버 - client의 요청 1회만 반응

from socket import *

serverSock = socket(AF_INET,SOCK_STREAM) 
#Stream방식의 유형을 찾는것 socket(소켓종류, 소켓유형): 소켓객체 만든 것

serverSock.bind(('127.0.0.1', 9999)) #ip주소와 포트번호 연결
serverSock.listen(1) #TCP 리스너 설정 1~5까지 설정

print('server start....')

conn, addr = serverSock.accept() #시스템에 의해서 반응이 주어짐 - callback함수(ajax처럼)
print('client addr: ',addr)
print('from client message: ',conn.recv(1024).decode()) 
#클라이언트로부터 바이트 단위 문자열 수신된 내용 출력

conn.close()
serverSock.close()​

soc1_server가 soc1_client 요청을 기다리고 있음

<클라이언트 실행 시 서버출력결과>

<soc1_client>
# 1회 접속용 클라이언트 소스코드
#서버를 먼저 실행시키고 클라이언트 실행

from socket import *

clientSock = socket(AF_INET,SOCK_STREAM)
clientSock.connect(('127.0.0.1', 9999))
clientSock.sendall('안녕 반가워'.encode(encoding='utf-8', errors='strict'))
clientSock.close()​
soc1_client의 요청을 받고 soc1_server 종료

 

예제2) 서버 서비스가 계속 유지되는 에코 서버(Echo Server): 다수의 클라이언트가 하나의 서버와 계속해서 접속가능 – while True: 로 무한루프 사용

<서버실행 시 서버 출력 결과>

<soc2_server>
#서버 서비스 계속 유지
import socket 
import sys

HOST = '' #가용할 host 알아서 입력
PORT = 8888

serverSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

try:
    serverSock.bind((HOST, PORT)) #bind는 무조건 튜플로 받기
    print('server start....')
    serverSock.listen(5) #클라이언트 동시 접속 수:1 ~ 5
    while(True):
        conn, addr = serverSock.accept()
        print('client info: ', addr[0], addr[1])
        print(conn.recv(1024).decode()) #클라이언트가 전송한 메세지 수신 후 출력
        
        #전송
        conn.send(('from server: ' + str(addr[1]) + ' 너도 파이팅').encode('utf_8'))
  
except socket.error as err:
    print('soc err: ', err)
    
except Exception as e:
    print('err: ',e)
    
finally:
    serverSock.close()
    conn.close()​

soc2_server가 soc2_client 요청을 기다리고 있음

<클라이언트 실행 시 서버출력결과>

<soc2_client>
# 1회 접속용 클라이언트 소스코드
#서버를 먼저 실행시키고 클라이언트 실행

from socket import *

clientSock = socket(AF_INET,SOCK_STREAM)
clientSock.connect(('127.0.0.1', 8888))
clientSock.sendall('안녕 반가워'.encode(encoding='utf-8'))

#서버로부터 메세지 받기
re_msg = clientSock.recv(1024).decode()

print('수신자료: ',re_msg)

clientSock.close()​

soc2_client의 요청을 받고 soc2_server 종료

 

[참고]

파이썬 소켓 통신 - kwon | kwon's Blog (kyu9341.github.io)

 

python의 soocket 통신시 send()와 sendall() 차이에 대해서 :: 코드 조각-Android, Java, Spring, JavaScript, C#, C, C++, PHP, HTML, CSS, Delphi (tistory.com)

 

파이썬 소켓 연결 사용법 · Wireframe (soooprmx.com)

 

 

'Python' 카테고리의 다른 글

16. pandas - (1) 개요, Series  (0) 2021.05.01
15. 멀티스레드, 멀티프로세스  (0) 2021.05.01
13. 원격(remote) db연동 – MariaDB  (0) 2021.04.29
12. GUI(윈도우 프로그래밍)  (0) 2021.04.29
11. 예외처리  (0) 2021.04.29

관련글 더보기