2011-02-24 40 views
38

Tôi đã cố gắng kết nối ổ cắm (ổ cắm máy chủ) tại số cổng 8000. Nó hoạt động và đã làm việc cho tôi. Ở cuối mã, tôi cũng đóng ổ cắm. Ngay sau đó, tôi chạy mã của tôi một lần nữa và nó cho tôi thấy rằng địa chỉ đã được sử dụng. Tôi đã in ý nghĩa của các giá trị lỗi strerror(errno); để xem mã của tôi có hoạt động đúng tại mỗi điểm hay không. Để kiểm tra xem cổng có miễn phí không, tôi đã kiểm tra nó bằng cách sử dụng netstat nhưng nó cho thấy rằng số cổng 8000 là miễn phí. Nó đã xảy ra với tôi rất nhiều lần. Mỗi lần tôi đợi thêm vài giây nữa và sau đó nó bắt đầu hoạt động trở lại. Tôi đang sử dụng ngôn ngữ c. Vì vậy, lý do gì cho hành vi này bởi hệ điều hành của tôi.Lỗi: Địa chỉ đã được sử dụng trong khi cổng kết nối có địa chỉ nhưng số cổng được hiển thị miễn phí bởi `netstat`

Sau một vài giây nữa, tôi chạy mã và sau đó nó hoạt động.

[email protected]:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success 
File open: Success 
Socket Bind: Address already in use 
Socket Listen: Address already in use 
^C 
[email protected]:~/Desktop/testing$ sudo netstat -lntp 
Active Internet connections (only servers) 
Proto Recv-Q Send-Q Local Address   Foreign Address   State  PID/Program name 
tcp  0  0 0.0.0.0:80    0.0.0.0:*    LISTEN  1348/lighttpd 
tcp  0  0 0.0.0.0:22    0.0.0.0:*    LISTEN  984/sshd   
tcp  0  0 127.0.0.1:631   0.0.0.0:*    LISTEN  1131/cupsd  
tcp  0  0 0.0.0.0:3306   0.0.0.0:*    LISTEN  1211/mysqld  
tcp6  0  0 :::22     :::*     LISTEN  984/sshd   
tcp6  0  0 ::1:631     :::*     LISTEN  1131/cupsd  
[email protected]:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success 
File open: Success 
Socket Bind: Address already in use 
Socket Listen: Address already in use 
^C 
[email protected]:~/Desktop/testing$ 

Trả lời

44

Tôi cũng gặp vấn đề tương tự. Đó là bởi vì bạn đang đóng kết nối của bạn vào ổ cắm, nhưng không phải là ổ cắm. Ổ cắm có thể vào trạng thái TIME_WAIT (để đảm bảo tất cả dữ liệu đã được truyền, TCP đảm bảo việc phân phối nếu có thể) and take up to 4 minutes to release.

hoặc, đối với một lời giải thích chi tiết REALLY/kỹ thuật, check this link

Nó có thể gây phiền nhiễu để chắc chắn, nhưng không có cách nào thực xung quanh nó và nó không phải là một lỗi.

+0

cảm ơn câu trả lời có liên kết để đáp ứng truy vấn của tôi. – Durin

+9

có một giải pháp khả thi trên trang bạn đã liên kết. Bạn có thể sử dụng tùy chọn SO_REUSEADDR cho socket. xem setsockopt ở đây: http://linux.die.net/man/3/setsockopt – Vereb

+1

"không có cách nào thực sự xung quanh nó và nó không phải là một lỗi", thích nó: P –

16

Hãy thử netstat như sau: netstat -ntp, không có -l. Nó sẽ hiển thị kết nối tcp ở trạng thái TIME_WAIT.

+3

Tốt hơn, sử dụng 'ss -npt'. – user611775

5

Chỉ cần gõ

unlink [SOCKET NAME] 

tại nhà ga, sau đó các lỗi không còn nên tồn tại.

1

Ngay cả câu trả lời của icfantv cho câu hỏi này cũng đã hoàn hảo, tôi vẫn còn nhiều phát hiện trong bài kiểm tra của mình.

Là một ổ cắm máy chủ trong trạng thái nghe, nếu nó chỉ ở trạng thái nghe và thậm chí nó chấp nhận yêu cầu và nhận dữ liệu từ phía máy khách, nhưng không có bất kỳ hành động gửi dữ liệu nào. Chúng tôi vẫn có thể khởi động lại máy chủ cùng một lúc sau khi nó dừng lại. Nhưng nếu bất kỳ hành động gửi dữ liệu nào xảy ra ở phía máy chủ cho máy khách, thì khởi động lại cùng một dịch vụ (cùng cổng) sẽ có lỗi này: (Địa chỉ đã được sử dụng).

Tôi nghĩ điều này là do nguyên tắc thiết kế TCP/IP. Khi máy chủ gửi dữ liệu trở lại máy khách, nó phải đảm bảo gửi dữ liệu thành công, để thực hiện điều này, hệ điều hành (Linux) cần giám sát kết nối ngay cả khi ứng dụng máy chủ đóng socket này. Nhưng tôi vẫn tin rằng thiết kế socket hạt nhân có thể cải thiện vấn đề này.

14

Tôi biết nó được một thời gian kể từ khi câu hỏi được hỏi nhưng tôi đã có thể tìm ra một giải pháp:

int sockfd; 
int option = 1; 
sockfd = socket(AF_INET, SOCK_STREAM, 0); 
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); 

này thiết lập các ổ cắm có thể được tái sử dụng ngay lập tức.

Tôi xin lỗi nếu điều này là "sai".Tôi không phải là rất có kinh nghiệm với ổ cắm

+0

Tôi thích cách bạn đặt 'sai' trong dấu ngoặc kép, ngụ ý rằng bất kỳ ai không đồng ý với bạn đều sai. – byxor

+6

các dấu ngoặc kép đã được nhiều hơn một "nếu nó hoạt động nó không sai" loại điều. Tôi nhận ra rằng có lẽ không phải là cách ưa thích và nếu có ai biết "đúng" cách tôi sẽ được quan tâm để nghe. – Supamee

0

lỗi tôi nhận được là:

cockpit.socket: Failed to listen on sockets: Address already in use 

sửa chữa tôi phát hiện ra là:

  1. tôi phải vô hiệu hóa selinux
  2. trong/usr/dịch vụ lib/systemd/system/cockpit tôi đã thay đổi đường dây :

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t 
    

    tới:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    

như vậy là bạn có thể thấy tôi lấy ra lập luận về selinux sau đó tôi chạy:

systemctl daemon-reload 
systemctl start cockpit.service 

sau đó tôi duyệt đến:

tôi chấp nhận chứng chỉ tự ký và là có thể đăng nhập thành công vào buồng lái và sử dụng nó bình thường.

đây là tất cả trên máy fedora25. cổng 9090 đã được thêm được sử dụng firewall-cmd

2

Như đã nói, ổ cắm của bạn có thể nhập vào trạng thái TIME_WAIT. Vấn đề này được mô tả rõ ràng bởi Thomas A. Phạt tiềnhere.

Để tóm tắt, ổ cắm đóng sơ đồ quá trình tiếp theo dưới đây:

Socket closing process

Thomas nói:

Looking at the diagram above, it is clear that TIME_WAIT can be avoided if the remote end initiates the closure. So the server can avoid problems by letting the client close first. The application protocol must be designed so that the client knows when to close. The server can safely close in response to an EOF from the client, however it will also need to set a timeout when it is expecting an EOF in case the client has left the network ungracefully. In many cases simply waiting a few seconds before the server closes will be adequate.

Sử dụng SO_REUSEADDR thường được gợi ý trên internet, nhưng Thomas add:

Oddly, using SO_REUSEADDR can actually lead to more difficult "address already in use" errors. SO_REUSADDR permits you to use a port that is stuck in TIME_WAIT , but you still can not use that port to establish a connection to the last place it connected to. What? Suppose I pick local port 1010, and connect to foobar.com port 300, and then close locally, leaving that port in TIME_WAIT . I can reuse local port 1010 right away to connect to anywhere except for foobar.com port 300.

0

Đối với AF_UNIX bạn có thể sử dụng hủy liên kết cuộc gọi (đường dẫn); sau khi khóa close() trong ứng dụng "máy chủ"

Các vấn đề liên quan