TCP / IP 네트워크의 클라이언트 소켓에 관한 질문이 있습니다. 내가 사용한다고 해보자
try:
comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(1)
try:
comSocket.bind(('', 5555))
comSocket.connect()
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(2)
생성 된 소켓은 포트 5555에 바인딩됩니다. 문제는 연결을 종료 한 후
comSocket.shutdown(1)
comSocket.close()
wireshark를 사용하면 양쪽에서 FIN, ACK 및 ACK로 소켓이 닫혀있는 것을 볼 수 있습니다. 포트를 다시 사용할 수 없습니다. 다음과 같은 오류가 발생합니다.
[ERROR] Address already in use
다음 번에 동일한 포트를 계속 사용할 수 있도록 포트를 즉시 지우는 방법이 궁금합니다.
comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
setsockopt가 문제를 해결할 수없는 것 같습니다. 감사합니다!
답변
SO_REUSEADDR
소켓을 바인딩하기 전에 소켓 옵션을 사용해보십시오 .
comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
편집 :
여전히 문제가있는 것 같습니다. SO_REUSEADDR
작동하지 않는 경우 가 있습니다. 소켓을 바인드하고 동일한 대상 ( SO_REUSEADDR
활성화 된 상태)에 다시 연결하려고하면TIME_WAIT
하면 여전히 유효합니다. 그러나 다른 호스트 : 포트에 연결할 수 있습니다.
몇 가지 해결책이 떠 오릅니다. 다시 연결할 수있을 때까지 계속 재 시도 할 수 있습니다. 또는 클라이언트가 (서버가 아닌) 소켓 닫기를 시작하면 마술처럼 작동합니다.
답변
다음은 내가 테스트 한 완전한 코드이며 절대적으로 “이미 사용중인 주소”오류를 표시하지 않습니다. 이를 파일에 저장하고 제공하려는 HTML 파일의 기본 디렉토리 내에서 파일을 실행할 수 있습니다. 또한 서버를 시작하기 전에 프로그래밍 방식으로 디렉토리를 변경할 수 있습니다.
import socket
import SimpleHTTPServer
import SocketServer
# import os # uncomment if you want to change directories within the program
PORT = 8000
# Absolutely essential! This ensures that socket resuse is setup BEFORE
# it is bound. Will avoid the TIME_WAIT issue
class MyTCPServer(SocketServer.TCPServer):
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = MyTCPServer(("", PORT), Handler)
# os.chdir("/My/Webpages/Live/here.html")
httpd.serve_forever()
# httpd.shutdown() # If you want to programmatically shut off the server
답변
TCPServer
또는을 사용하여 문제가 발생하는 SimpleHTTPServer
경우 SocketServer.TCPServer.allow_reuse_address
(python 2.7.x) 또는 socketserver.TCPServer.allow_reuse_address
(python 3.x) 속성을 재정의하십시오.
class MyServer(SocketServer.TCPServer):
allow_reuse_address = True
server = MyServer((HOST, PORT), MyHandler)
server.serve_forever()
답변
이 링크 에 따르면
실제로 SO_REUSEADDR 플래그는 훨씬 더 큰 결과를 초래할 수 있습니다. SO_REUSADDR은 TIME_WAIT에 멈춘 포트를 사용할 수 있도록 허용하지만 여전히 해당 포트를 사용하여 마지막으로 연결된 위치에 연결할 수는 없습니다. 뭐? 로컬 포트 1010을 선택하고 foobar.com 포트 300에 연결 한 다음 로컬에서 닫고 해당 포트를 TIME_WAIT에 남겨 둔다고 가정합니다. 로컬 포트 1010을 즉시 재사용하여 foobar.com 포트 300을 제외한 모든 곳에 연결할 수 있습니다.
그러나 원격 끝이 종료 (닫기 이벤트)를 시작하도록함으로써 TIME_WAIT 상태를 완전히 피할 수 있습니다. 따라서 서버는 클라이언트를 먼저 닫아 문제를 피할 수 있습니다. 응용 프로그램 프로토콜은 클라이언트가 종료시기를 알 수 있도록 설계되어야합니다. 서버는 클라이언트의 EOF에 대한 응답으로 안전하게 닫을 수 있지만 클라이언트가 네트워크를 비정상적으로 떠난 경우 EOF를 예상 할 때 시간 제한을 설정해야합니다. 많은 경우 서버가 닫히기 전에 몇 초만 기다리면 충분합니다.
또한 네트워킹 및 네트워크 프로그래밍에 대해 자세히 알아 보도록 조언합니다. 이제 최소한 tcp 프로토콜이 어떻게 작동하는지 확인해야합니다. 프로토콜은 매우 사소하고 작기 때문에 미래에 많은 시간을 절약 할 수 있습니다.
와 netstat
명령을 어떤 프로그램 ((program_name, pid) 튜플)이 어떤 포트에 바인딩되어 있으며 소켓 현재 상태는 무엇인지 쉽게 확인할 수 있습니다 : TIME_WAIT, CLOSING, FIN_WAIT 등.
Linux 네트워크 구성에 대한 정말 좋은 설명은 /server/212093/how-to-reduce-number-of-sockets-in-time-wait 에서 찾을 수 있습니다 .
답변
바인딩하기 전에 allow_reuse_address를 설정해야합니다. SimpleHTTPServer 대신 다음 스 니펫을 실행하십시오.
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler, bind_and_activate=False)
httpd.allow_reuse_address = True
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()
이것은 플래그를 설정하기 전에 서버가 바인딩되는 것을 방지합니다.
답변
Felipe Cruze가 언급했듯이 바인딩하기 전에 SO_REUSEADDR을 설정해야합니다. 다른 사이트에서 솔루션을 찾았습니다-다른 사이트의 솔루션, 아래에 재현 됨
문제는 주소가 소켓에 바인딩되기 전에 SO_REUSEADDR 소켓 옵션을 설정해야한다는 것입니다. ThreadingTCPServer를 서브 클래 싱하고 다음과 같이 server_bind 메서드를 재정 의하여이를 수행 할 수 있습니다.
import SocketServer, 소켓 클래스 MyThreadingTCPServer (SocketServer.ThreadingTCPServer) : def server_bind (self) : self.socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind (self.server_address)
답변
이 예외에 대한 또 다른 이유를 찾았습니다. Spyder IDE (제 경우에는 Raspbian의 Spyder3)에서 응용 프로그램을 실행하고 프로그램이 ^ C 또는 예외로 종료 될 때 소켓은 여전히 활성 상태였습니다.
sudo netstat -ap | grep 31416
tcp 0 0 0.0.0.0:31416 0.0.0.0:* LISTEN 13210/python3
프로그램을 다시 실행하면 “이미 사용중인 주소”가 발견되었습니다. IDE는 이전 ‘실행’에서 사용 된 소켓을 찾는 별도의 프로세스로 새로운 ‘실행’을 시작하는 것 같습니다.
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
도움이되지 않았습니다.
킬링 프로세스 13210이 도움이되었습니다. 다음과 같은 명령 줄에서 파이썬 스크립트 시작
python3 <app-name>.py
SO_REUSEADDR이 true로 설정되면 항상 잘 작동했습니다. 새로운 Thonny IDE 또는 Idle3 IDE에는이 문제가 없었습니다.