[PYTHON] 파이썬 : 바인딩 소켓 : "이미 사용중인 주소"
PYTHON파이썬 : 바인딩 소켓 : "이미 사용중인 주소"
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가 문제를 해결할 수없는 것 같습니다. 고맙습니다!
해결법
-
==============================
1.소켓을 바인딩하기 전에 SO_REUSEADDR 소켓 옵션을 사용해보십시오.
소켓을 바인딩하기 전에 SO_REUSEADDR 소켓 옵션을 사용해보십시오.
comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
편집하다: 너 아직도 이걸로 문제가있는 것 같아. SO_REUSEADDR이 작동하지 않는 경우가 있습니다. 소켓을 바인드하고 동일한 대상 (SO_REUSEADDR 사용 가능)에 다시 연결하려고하면 TIME_WAIT가 여전히 유효합니다. 그러나 다른 호스트 : 포트에 연결할 수 있습니다.
두 가지 해결책이 떠오른다. 다시 연결될 때까지 계속 재 시도 할 수 있습니다. 또는 클라이언트가 서버가 아닌 소켓의 닫기를 시작하면 마술처럼 작동해야합니다.
-
==============================
2.여기에 테스트를 거친 코드가 있으며 "주소가 이미 사용 중입니다"라는 오류는 절대 발생하지 않습니다. 이 파일을 파일에 저장하고 제공 할 HTML 파일의 기본 디렉토리에서 파일을 실행할 수 있습니다. 또한 서버를 시작하기 전에 프로그래밍 방식으로 디렉터리를 변경할 수 있습니다
여기에 테스트를 거친 코드가 있으며 "주소가 이미 사용 중입니다"라는 오류는 절대 발생하지 않습니다. 이 파일을 파일에 저장하고 제공 할 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
-
==============================
3.실제로 SO_REUSEADDR 플래그는 훨씬 더 큰 결과를 초래할 수 있습니다. SO_REUSADDR을 사용하면 TIME_WAIT에 걸린 포트를 사용할 수 있지만 그 포트를 사용하여 연결된 마지막 위치에 대한 연결을 설정할 수는 없습니다. 뭐? 로컬 포트 1010을 선택하고 foobar.com 포트 300에 연결 한 다음 로컬에서 닫고 해당 포트를 TIME_WAIT에 남겨 두었다고 가정합니다. 로컬 포트 1010을 바로 재사용하여 foobar.com 포트 300을 제외하고 어디에도 연결할 수 있습니다.
실제로 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) tuple)이 어떤 포트에 바인드되고 소켓 현재 상태 (TIME_WAIT, CLOSING, FIN_WAIT 등)가 무엇인지 쉽게 알 수 있습니다.
리눅스 네트워크 설정에 대한 좋은 설명은 https://serverfault.com/questions/212093/how-to-reduce-number-of-socket-in-time-wait에서 찾을 수 있습니다.
-
==============================
4.바인딩하기 전에 allow_reuse_address를 설정해야합니다. SimpleHTTPServer 대신 다음 스 니펫을 실행하십시오.
바인딩하기 전에 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()
이렇게하면 플래그를 설정하기 전에 서버가 바인딩되지 않습니다.
-
==============================
5.TCPServer 또는 SimpleHTTPServer를 사용하여 문제가 발생하는 경우, SocketServer.TCPServer.allow_reuse_address (python 2.7.x)를 오버라이드 (override)합니다. 또는 socketserver.TCPServer.allow_reuse_address (파이썬 3.x) 속성
TCPServer 또는 SimpleHTTPServer를 사용하여 문제가 발생하는 경우, SocketServer.TCPServer.allow_reuse_address (python 2.7.x)를 오버라이드 (override)합니다. 또는 socketserver.TCPServer.allow_reuse_address (파이썬 3.x) 속성
class MyServer(SocketServer.TCPServer): allow_reuse_address = True server = MyServer((HOST, PORT), MyHandler) server.serve_forever()
-
==============================
6.socket.socket ()은 socket.bind () 전에 실행하고 REUSEADDR을 사용한다고합니다.
socket.socket ()은 socket.bind () 전에 실행하고 REUSEADDR을 사용한다고합니다.
-
==============================
7.Felipe Cruze가 언급했듯이 바인딩하기 전에 SO_REUSEADDR을 설정해야합니다. 다른 사이트의 솔루션을 찾았습니다 - 아래에 재현 된 다른 사이트의 솔루션
Felipe Cruze가 언급했듯이 바인딩하기 전에 SO_REUSEADDR을 설정해야합니다. 다른 사이트의 솔루션을 찾았습니다 - 아래에 재현 된 다른 사이트의 솔루션
import SocketServer, socket class MyThreadingTCPServer(SocketServer.ThreadingTCPServer): def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address)
-
==============================
8.나를 위해 더 나은 해결책은 다음과 같습니다. 연결을 닫기위한 시도가 서버에 의해 수행 되었기 때문에 setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)는 아무 효과가 없었고 TIME_WAIT는 동일한 포트에서 오류가 발생하여 새 연결을 피했습니다.
나를 위해 더 나은 해결책은 다음과 같습니다. 연결을 닫기위한 시도가 서버에 의해 수행 되었기 때문에 setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)는 아무 효과가 없었고 TIME_WAIT는 동일한 포트에서 오류가 발생하여 새 연결을 피했습니다.
[Errno 10048]: Address already in use. Only one usage of each socket address (protocol/IP address/port) is normally permitted
마지막으로 솔루션을 사용하여 OS가 포트 자체를 선택하게하고 선행이 TIME_WAIT 인 경우 다른 포트가 사용됩니다.
나는 바꿨다.
self._socket.bind((guest, port))
와:
self._socket.bind((guest, 0))
그것은 TCP 주소의 python 소켓 문서에 나와 있듯이 :
-
==============================
9.나는 당신이 이미 대답을 받아 들였지만, 문제는 클라이언트 소켓에서 bind ()를 호출하는 것과 관련이 있다고 생각한다. 이것은 괜찮지 만 bind ()와 shutdown ()은 잘 작동하지 않는 것 같습니다. 또한 SO_REUSEADDR은 일반적으로 청취 소켓과 함께 사용됩니다. 즉 서버 측에서는
나는 당신이 이미 대답을 받아 들였지만, 문제는 클라이언트 소켓에서 bind ()를 호출하는 것과 관련이 있다고 생각한다. 이것은 괜찮지 만 bind ()와 shutdown ()은 잘 작동하지 않는 것 같습니다. 또한 SO_REUSEADDR은 일반적으로 청취 소켓과 함께 사용됩니다. 즉 서버 측에서는
당신은 ip / port를 connect ()에 전달해야합니다. 이렇게 :
comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) comSocket.connect(('', 5555))
bind ()를 호출하지 말고 SO_REUSEADDR을 설정하지 마십시오.
-
==============================
10.물론 개발 환경에서 또 하나의 솔루션은 그것을 사용하는 프로세스를 죽이는 것입니다.
물론 개발 환경에서 또 하나의 솔루션은 그것을 사용하는 프로세스를 죽이는 것입니다.
def serve(): server = HTTPServer(('', PORT_NUMBER), BaseHTTPRequestHandler) print 'Started httpserver on port ' , PORT_NUMBER server.serve_forever() try: serve() except Exception, e: print "probably port is used. killing processes using given port %d, %s"%(PORT_NUMBER,e) os.system("xterm -e 'sudo fuser -kuv %d/tcp'" % PORT_NUMBER) serve() raise e
-
==============================
11.가장 좋은 방법은 터미널 fuser -k [PORT NUMBER] / tcp를 입력하여 해당 포트에서 프로세스를 종료하는 것입니다. fuser -k 5001 / tcp.
가장 좋은 방법은 터미널 fuser -k [PORT NUMBER] / tcp를 입력하여 해당 포트에서 프로세스를 종료하는 것입니다. fuser -k 5001 / tcp.
-
==============================
12.나는이 예외에 대한 또 다른 이유를 발견했다. Spyder IDE (제 경우에는 Raspbian의 Spyder3)에서 응용 프로그램을 실행할 때 프로그램이 ^ C 또는 예외로 종료되었지만 소켓은 여전히 활성 상태입니다.
나는이 예외에 대한 또 다른 이유를 발견했다. 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
프로그램을 다시 실행하면 "Address already in use"가 발견되었습니다. IDE는 새로운 '실행'을 이전 '실행'에서 사용 된 소켓을 찾는 별도의 프로세스로 시작하는 것으로 보입니다.
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
도와주지 않았어.
Killing 프로세스 13210이 도움이되었습니다. 명령 줄에서 파이썬 스크립트 시작하기
python3 <app-name>.py
SO_REUSEADDR이 true로 설정된 경우 항상 잘 작동합니다. 새로운 Thonny IDE 또는 Idle3 IDE에는이 문제가 없습니다.
from https://stackoverflow.com/questions/6380057/python-binding-socket-address-already-in-use by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 파이썬 2 개체를 파이썬 3으로 풀어주기 (0) | 2018.10.04 |
---|---|
[PYTHON] 파이썬에서 float의 이진 표현 (16 진수가 아닌 비트) (0) | 2018.10.04 |
[PYTHON] __str__ 및 __repr__의 목적은 무엇입니까? (0) | 2018.10.04 |
[PYTHON] 파이썬에서 개인 및 보호 된 메소드의 상속 (0) | 2018.10.04 |
[PYTHON] 고급 중첩 목록 이해 구문 (0) | 2018.10.04 |