수색…


소개

많은 프로그래밍 언어는 소켓을 사용하여 프로세스간에 또는 장치간에 통신합니다. 이 항목에서는 일반적인 네트워킹 프로토콜을 통해 데이터를주고받을 수 있도록 Python의 소켓 모듈을 올바르게 사용하는 방법에 대해 설명합니다.

매개 변수

매개 변수 기술
socket.AF_UNIX 유닉스 소켓
socket.AF_INET IPv4
socket.AF_INET6 IPv6
socket.SOCK_STREAM TCP
socket.SOCK_DGRAM UDP

UDP를 통한 데이터 전송

UDP는 비 연결 프로토콜입니다. 다른 프로세스 나 컴퓨터에 대한 메시지는 어떤 종류의 연결도 설정하지 않고 전송됩니다. 귀하의 메시지를 수신 한 경우 자동 확인이 없습니다. UDP는 일반적으로 대기 시간에 민감한 응용 프로그램이나 네트워크 전체 방송을 보내는 응용 프로그램에 사용됩니다.

다음 코드는 UDP를 사용하여 localhost 포트 6667에서 청취하는 프로세스에 메시지를 보냅니다.

UDP는 비 연결 이기 때문에 보내기 후에 소켓을 "닫을 필요가 없습니다.

from socket import socket, AF_INET, SOCK_DGRAM
s = socket(AF_INET, SOCK_DGRAM)
msg = ("Hello you there!").encode('utf-8')  # socket.sendto() takes bytes as input, hence we must encode the string first.
s.sendto(msg, ('localhost', 6667)) 

UDP를 통한 데이터 수신

UDP는 비 연결 프로토콜입니다. 즉, 메시지를 보내는 피어는 메시지를 보내기 전에 연결을 설정할 필요가 없습니다. socket.recvfrom 은 튜플 ( msg [소켓이받은 메시지], addr [송신자의 주소])을 리턴한다.

socket 모듈만을 사용하는 UDP 서버 :

from socket import socket, AF_INET, SOCK_DGRAM
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind(('localhost', 6667))

while True:
    msg, addr = sock.recvfrom(8192)  # This is the amount of bytes to read at maximum
    print("Got message from %s: %s" % (addr, msg))

다음은 socketserver.UDPServer 사용하는 다른 구현입니다.

from socketserver import BaseRequestHandler, UDPServer

class MyHandler(BaseRequestHandler):
    def handle(self):
        print("Got connection from: %s" % self.client_address)
        msg, sock = self.request
        print("It said: %s" % msg)
        sock.sendto("Got your message!".encode(), self.client_address) # Send reply

serv = UDPServer(('localhost', 6667), MyHandler)
serv.serve_forever()

기본적으로 sockets 차단됩니다. 즉, 스크립트 실행은 소켓이 데이터를 수신 할 때까지 대기합니다.

TCP를 통한 데이터 전송

여러 모듈을 사용하여 인터넷을 통해 데이터를 전송할 수 있습니다. 소켓 모듈은 다른 컴퓨터 또는 프로세스에서 데이터를 보내거나받는 책임이있는 기본 운영 체제 작업에 대한 하위 수준 액세스를 제공합니다.

다음 코드는 바이트 문자열 b'Hello' 를 호스트 localhost의 포트 6667에서 수신 대기하는 TCP 서버로 보내고 완료되면 연결을 닫습니다.

from socket import socket, AF_INET, SOCK_STREAM
s = socket(AF_INET, SOCK_STREAM)
s.connect(('localhost', 6667))  # The address of the TCP server listening
s.send(b'Hello')
s.close()

소켓 출력은 기본적으로 블로킹입니다. 즉, 프로그램은 연결이 완료되고 작업이 완료 될 때까지 호출을 기다립니다. 연결의 경우 서버가 실제로 연결을 수락 함을 의미합니다. 보내기의 경우 운영 체제가 나중에 보낼 데이터를 대기열에 저장할 버퍼 공간이 충분하다는 의미입니다.

소켓은 사용 후 항상 닫아야합니다.

멀티 스레드 TCP 소켓 서버

인수없이 실행하면이 프로그램은 포트 5000 127.0.0.1 에 대한 연결을 수신하는 TCP 소켓 서버를 시작합니다. 서버는 별도의 스레드에서 각 연결을 처리합니다.

-c 인수를 사용하여 실행하면이 프로그램은 서버에 연결하고 클라이언트 목록을 읽고이를 인쇄합니다. 클라이언트 목록은 JSON 문자열로 전송됩니다. 클라이언트 이름은 -n 인수를 전달하여 지정할 수 있습니다. 다른 이름을 전달하면 클라이언트 목록에 미치는 영향을 관찰 할 수 있습니다.

client_list.py

import argparse
import json
import socket
import threading

def handle_client(client_list, conn, address):
    name = conn.recv(1024)
    entry = dict(zip(['name', 'address', 'port'], [name, address[0], address[1]]))
    client_list[name] = entry
    conn.sendall(json.dumps(client_list))
    conn.shutdown(socket.SHUT_RDWR)
    conn.close()

def server(client_list):
    print "Starting server..."
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('127.0.0.1', 5000))
    s.listen(5)
    while True:
        (conn, address) = s.accept()
        t = threading.Thread(target=handle_client, args=(client_list, conn, address))
        t.daemon = True
        t.start()

def client(name):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 5000))
    s.send(name)
    data = s.recv(1024)
    result = json.loads(data)
    print json.dumps(result, indent=4)

def parse_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', dest='client', action='store_true')
    parser.add_argument('-n', dest='name', type=str, default='name')
    result = parser.parse_args()
    return result

def main():
    client_list = dict()
    args = parse_arguments()
    if args.client:
        client(args.name)
    else:
        try:
            server(client_list)
        except KeyboardInterrupt:
            print "Keyboard interrupt"

if __name__ == '__main__':
    main()

서버 출력

$ python client_list.py
Starting server...

클라이언트 출력

$ python client_list.py -c -n name1
{
    "name1": {
        "address": "127.0.0.1", 
        "port": 62210, 
        "name": "name1"
    }
}

수신 버퍼는 1024 바이트로 제한됩니다. 클라이언트 목록의 JSON 문자열 표현이이 크기를 초과하면 잘립니다. 이로 인해 다음과 같은 예외가 발생합니다.

ValueError: Unterminated string starting at: line 1 column 1023 (char 1022)

Linux의 원시 소켓

먼저 네트워크 카드의 자동 체크섬을 비활성화합니다.

sudo ethtool -K eth1 tx off

그런 다음 SOCK_RAW 소켓을 사용하여 패킷을 보냅니다.

#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth1", 0))

# We're putting together an ethernet frame here, 
# but you could have anything you want instead
# Have a look at the 'struct' module for more 
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"

s.send(dst_addr+src_addr+ethertype+payload+checksum)


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow