Python Language
소켓
수색…
소개
많은 프로그래밍 언어는 소켓을 사용하여 프로세스간에 또는 장치간에 통신합니다. 이 항목에서는 일반적인 네트워킹 프로토콜을 통해 데이터를주고받을 수 있도록 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)