2012-07-05 26 views
5

Ứng dụng của chúng tôi sử dụng cách sử dụng ổ cắm không chặn với các hoạt động kết nối và chọn (mã c). Mã pusedo như sau:tcp kết nối không thành công ngẫu nhiên dưới tải cao

unsigned int ConnectToServer(struct sockaddr_in *pSelfAddr,struct sockaddr_in *pDestAddr) 
    { 
     int sktConnect = -1; 
     sktConnect = socket(AF_INET,SOCK_STREAM,0); 
     if(sktConnect == INVALID_SOCKET) 
      return -1; 
     fcntl(sktConnect,F_SETFL,fcntl(sktConnect,F_GETFL) | O_NONBLOCK); 
     if(pSelfAddr != 0) 
     { 
      if(bind(sktConnect,(const struct sockaddr*)(void *)pSelfAddr,sizeof(*pSelfAddr)) != 0) 
      { 
       closesocket(sktConnect); 
       return -1; 
      } 
     } 
     errno = 0; 
     int nRc = connect(sktConnect,(const struct sockaddr*)(void *)pDestAddr, sizeof(*pDestAddr)); 
     if(nrC != -1) 
     { 
      return sktConnect; 
     } 
     if(errno != EINPROGRESS) 
     { 
      int savedError = errno; 
      closesocket(sktConnect); 
      return -1; 
     } 
     fd_set scanSet; 
     FD_ZERO(&scanSet); 
     FD_SET(sktConnect,&scanSet); 
     struct timeval waitTime; 
     waitTime.tv_sec = 2; 
     waitTime.tv_usec = 0; 
     int tmp; 
     tmp = select(sktConnect +1, (fd_set*)0, &scanSet, (fd_set*)0,&waitTime); 
     if(tmp == -1 || !FD_ISSET(sktConnect,&scanSet)) 
     { 
      int savedErrorNo = errno; 
      writeLog("Connect %s failed after select, cause %d, error %s",inet_ntoa(pDestAddr->sin_addr),savedErrorNo,strerror(savedErrorNo)); 
      closesocket(sktConnect); 
      return -1; 
     } 
    .  .  .  .  .} 

Có 80 nút như vậy và ứng dụng kết nối với tất cả đồng đẳng của nó theo kiểu vòng tròn. Trong giai đoạn này, một số các nút là không thể kết nối (api - kết nối + chọn) với số lỗi 115.

Trong các bản ghi bên dưới (sản lượng tcpdump) cho kịch bản thành công, chúng ta có thể thấy (SYN, SYN + ACK, ACK) nhưng không có mục nhập nào thậm chí SYN có mặt cho nút không thành công trong nhật ký tcpdump.

Các bản ghi tcpdump là:

387937 2012-07-05 07:45:30.646514 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [SYN] Seq=0 Ack=0 Win=5792 Len=0 MSS=1460 TSV=1414450402 TSER=912308224 WS=8 
387947 2012-07-05 07:45:30.780762 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=912309754 TSER=1414450402 WS=8 
387948 2012-07-05 07:45:30.780773 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=1 Ack=1 Win=5888 Len=0 TSV=1414450435 TSER=912309754 
All the above three events indicate the success information. 
387949 2012-07-05 07:45:30.782652 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=1 Ack=1 Win=5888 Len=320 TSV=1414450436 TSER=912309754 
387967 2012-07-05 07:45:30.915615 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1 Ack=321 Win=6912 Len=0 TSV=912309788 TSER=1414450436 
388011 2012-07-05 07:45:31.362712 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=321 Ack=1 Win=5888 Len=320 TSV=1414450581 TSER=912309788 
388055 2012-07-05 07:45:31.495558 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1 Ack=641 Win=7936 Len=0 TSV=912309933 TSER=1414450581 
388080 2012-07-05 07:45:31.702336 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=1 Ack=641 Win=7936 Len=712 TSV=912309985 TSER=1414450581 
388081 2012-07-05 07:45:31.702350 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=641 Ack=713 Win=7424 Len=0 TSV=1414450666 TSER=912309985 
388142 2012-07-05 07:45:32.185612 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=713 Ack=641 Win=7936 Len=320 TSV=912310106 TSER=1414450666 
388143 2012-07-05 07:45:32.185629 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=641 Ack=1033 Win=8704 Len=0 TSV=1414450786 TSER=912310106 
388169 2012-07-05 07:45:32.362622 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [PSH, ACK] Seq=641 Ack=1033 Win=8704 Len=320 TSV=1414450831 TSER=912310106 
388212 2012-07-05 07:45:32.494833 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [ACK] Seq=1033 Ack=961 Win=9216 Len=0 TSV=912310183 TSER=1414450831 
388219 2012-07-05 07:45:32.501613 10.137.165.136  10.18.92.173   TCP  8441 > 33728 [PSH, ACK] Seq=1033 Ack=961 Win=9216 Len=356 TSV=912310185 TSER=1414450831 
388220 2012-07-05 07:45:32.501624 10.18.92.173   10.137.165.136  TCP  33728 > 8441 [ACK] Seq=961 Ack=1389 Win=10240 Len=0 TSV=1414450865 TSER=912310185 

Logs Ứng dụng thông báo lỗi trên kết nối (nghĩa là api - kết nối + chọn)

[5258: 2012-07-05 07:45:30]Connect [10.137.165.136 <- 10.18.92.173] success. 
[5258: 2012-07-05 07:45:32]Connect 10.137.165.137 fail after select, cause:115, error Operation now in progress. Check whether remote machine exist and the network is normal or not. 
[5258: 2012-07-05 07:45:32]Connect to server([10.137.165.137 <- 10.18.92.173], port=8441) Failed! 

bản ghi thành công tương ứng với 3 mục đầu tiên của tcpdump. Và thất bại đăng nhập mà không có sự kiện trong tcpdump

Câu hỏi của tôi là: Khi khách hàng khởi “kết nối” api đối với trường hợp thất bại, tôi không thể nhìn thấy bất kỳ sự kiện trong tcpdump tại phía khách hàng (thậm chí SYN ban đầu). Điều gì có thể là lý do của sự ngẫu nhiên này.

+0

khi bạn thoát 'tcpdump' bạn có thấy bất kỳ giá trị khác không cho' gói bị giảm bởi hạt nhân' hoặc 'gói bị bỏ bởi giao diện' không? –

Trả lời

2

Bạn đã nhấn EINPROGRESS. Từ trang người dùng connect:

Ổ cắm không thể chặn và kết nối không thể hoàn tất ngay lập tức. Có thể chọn (2) hoặc thăm dò ý kiến ​​(2) để hoàn thành bằng cách chọn ổ cắm để ghi. Sau khi chọn (2) biểu thị khả năng ghi, sử dụng getockopt (2) để đọc tùy chọn SO_ERROR ở mức SOL_SOCKET để xác định xem kết nối() đã hoàn tất thành công hay không thành công (SO_ERROR là một trong các mã lỗi thông thường được liệt kê ở đây, giải thích lý do cho sự thất bại).

Điều này nói rằng EINPROGRESS là chỉ báo cho biết hạt nhân không thể hoàn thành kết nối ngay bây giờ, mặc dù có các cổng cục bộ và định tuyến bộ nhớ cache. Dường như điều này xảy ra khi trạng thái socket chưa chuyển sang "ESTABLISHED". Chỉ cần đợi lại ổ cắm trong select, nhưng hãy gọi getsockopt sau đó để xem nếu connect của bạn đã hoàn tất chưa.

Vì lý do tại sao, socket chuyển sang trạng thái SYN_SENT trong khi kết nối, nhưng gói có thể vẫn nằm trong hàng đợi đầu ra và chưa thực sự đưa nó vào bộ đệm thiết bị mạng.

+0

Có tham số hạt nhân nào (tức là lớp ngăn xếp TCP/IP) mà khi được điều chỉnh có thể xử lý các loại mâu thuẫn này bằng cách mang lại sự vững chắc hơn trong hệ thống. Về cơ bản làm thế nào chúng ta có thể đảm bảo sự ổn định về hiệu suất trong những trường hợp như vậy? –

+1

@kumar_m_kiran: Không phải nếu bạn muốn kết nối không đồng bộ. Mỗi thiết bị cuối cùng sẽ đạt đến giới hạn về số lượng hoạt động mà nó có thể thực hiện một giây. Nếu bạn không muốn đối phó với tình trạng này, 'connect' trong chế độ chặn, và sau đó làm cho ổ cắm không chặn sau khi thành công. – jxh

0

Sau khi select() trả lại, bạn không thực sự tìm nạp trạng thái hiện tại của ổ cắm - bạn đang thấy giá trị cũ trong errno (còn lại từ cuộc gọi connect()). Nhiều khả năng select() của bạn chỉ đơn giản là quay trở lại sau thời gian chờ.

Bạn cần gọi số getsockopt(sktConnect, SOL_SOCKET, SO_ERROR, &err, ...) để nhận trạng thái thực tế của socket sau khi trả về select().

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