WIZnet Developer Forum

W5500 TCPMode send도중 SOCK_CLOSED Mode로 가버림

안녕하세요
w5500 Client TCP Mode에서 이유없이 SOCK_CLOSED 상태로 가버립니다.
서버 192.168.0.3 w5500 쪽 192.168.0.80 으로 1초에 한번씩 Packet Send 하는 경우 발생 합니다.
Test 용으로 send시에 Data Size를 1초에 1개씩 증가 하면서 보내는 시험을 하고 있습니다.

아래 것은 Server 단에서 wirewhark으로 마지막에 capture한것이구요
9935 1130.248643 192.168.0.80 192.168.0.3 TCP 155 5062→5062 [PSH, ACK] Seq=5233 Ack=18 Win=2048 Len=101
9937 1130.299937 192.168.0.3 192.168.0.80 TCP 54 5062→5062 [ACK] Seq=18 Ack=5334 Win=63460 Len=0
9952 1131.258632 192.168.0.80 192.168.0.3 TCP 156 5062→5062 [PSH, ACK] Seq=5334 Ack=18 Win=2048 Len=102
9954 1131.315577 192.168.0.3 192.168.0.80 TCP 54 5062→5062 [ACK] Seq=18 Ack=5436 Win=63358 Len=0

질의1)
loopback 예제를 보니 아래 처럼 되어 있습니다.
case SOCK_CLOSED:
#ifdef LOOPBACK_DEBUG
//printf("%d:UDP loopback start\r\n",sn);
#endif
if((ret = socket(sn, Sn_MR_UDP, port, 0x00)) != sn)
return ret;
이유없이 SOCK_CLOSED 로 갈 경우 다시 Socket을 Open 해야 된다는 것인가요?
그렇다면 정말로 끊고 싶을때는 어떻게 해야 하는지요?

질의2)
SOCK_CLOSED로 이유 없이 가는 경우 어디를 집중적으로 봐야 하는가요?
참고로 w5500 최신 driver로 Porting 했구요 STM32f103 CPU에 SPI통신으로 구현되어 있습니다.
빠른 답신 당부 드려요.
attachments 에 wireshark file 가이 보내 드렸습니다. txt->pcapng 고쳐서 보면 되요.
Server 단 OS는 windows Server
capture 20170222.txt (4.27 MB)

안녕하세요 :smiley:

질의1)
SOCK_CLOSED: 부분에서 socket을 open하는 이유는 연결후 close된상태이기도 하지만, 통신을하기전 초기상태이기 때문입니다.
connection전 준비단계라고 보시면 될거같습니다.


질의2)
TEST환경에 대해 좀더 상세하게 설명 부탁드립니다.
server : window - 192.168.0.3
client : w5500 - 192.168.0.80
client에서 server로 data를 1씩 증가시키면서 send로 판단되는데, 혼동이 됩니다.
test flow에 대해서도 자세히 설명 부탁드립니다.

wireshark를 첨부해주실때도 필터해서 캡쳐부탁드립니다.
wireshark를 켜두고 여러번 test하신거 같은데 어떤패킷들을 봐야하는건지 혼동이 됩니다.
패킷 우클릭->follow -> tcp stream을 누르면 해당 소켓의 통신에 대한 패킷만 display됩니다.
그상태에서 file->export specified pack-> (라디오박스)selected packet를 선택후 저장하시면 됩니다.

말씀하신 9935~9954에대해서만 봤을때는
fin이나 rst패킷은 보이지 않는것 같은데, 상태는 close 상태가 되었다는 말씀이신가요?
source를 수정하여서 어떤 부분에서 close함수가 호출된건지, 아니면 상태가 갑자기 바뀐건지 출력되록해서 확인해보시면 좋을 것같습니다.

감사합니다.

빠른 답변 감사 드립니다.
Server ip 192.168.0.3
w5500 ip 192.168.0.80
ip client mode로 사용
w5500 side 에서 1초 한번씩 Packet길이를 1개씩 증가 하면서 서버로 보내는 시험을 하였습니다.

Connection_tcpc 함수와 send 함수를 아래 처럼 만들었습니다.
Connection_tcpc 함수는 20ms 마다 주기적으로 호출 되도록 하였고, send 함수는 다른 task에서 보내는 구조 입니다.

int Connection_tcpc(unsigned char sn, uint16 port)
{

int32_t ret; // return value for SOCK_ERRORs

uint16_t size = 0, sentsize=0,destport;
unsigned char tcpc_Server_destip[4];

// Port number for TCP client (will be increased)
uint16_t any_port = ALARM_CLIENTPORT;

// Socket Status Transitions
// Check the W5500 Socket n status register (Sn_SR, The ‘Sn_SR’ controlled by Sn_CR command or Packet send/recv status)
switch(getSn_SR(sn))
{
case SOCK_ESTABLISHED :
if(getSn_IR(sn) & Sn_IR_CON) // Socket n interrupt register mask; TCP CON interrupt = connection with peer is successful
{
ch_status[sn] = 2;
IP_Connect_Led(YES);
#ifdef LOOPBACK_DEBUG
getSn_DIPR(sn, tcpc_Server_destip);
destport = getSn_DPORT(sn);
printf("%d: tcpc Connected to - %d.%d.%d.%d : %d\r\n",sn, tcpc_Server_destip[0], tcpc_Server_destip[1], tcpc_Server_destip[2], tcpc_Server_destip[3], destport);
#endif
setSn_IR(sn, Sn_IR_CON); // this interrupt should be write the bit cleared to ‘1’
}

     //////////////////////////////////////////////////////////////////////////////////////////////
     // Data Transaction Parts; Handle the [data receive and send] process
     //////////////////////////////////////////////////////////////////////////////////////////////
	 if((size = getSn_RX_RSR(sn)) > 0) // Sn_RX_RSR: Socket n Received Size Register, Receiving data length
            {
		if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE; // DATA_BUF_SIZE means user defined buffer size (array)
		ret = recv(sn, RX_BUF, size); // Data Receive process (H/W Rx socket buffer -> User's buffer)     
		if(ret <= 0) return ret; // If the received data length <= 0, receive failed and process end
            }
	 //////////////////////////////////////////////////////////////////////////////////////////////
     break;

  case SOCK_CLOSE_WAIT :

#ifdef LOOPBACK_DEBUG
printf("%d:CloseWait\r\n",sn);
#endif
if((ret=disconnect(sn)) != SOCK_OK) return ret;
#ifdef LOOPBACK_DEBUG
printf("%d:Socket Closed\r\n", sn);
#endif
break;

  case SOCK_INIT :

     if(Server_Monitoring_Req == TRUE)  // Server에서 요청된 Port로 접속
     {        
	    if( (ret = connect(sn, Server_destip, Server_Monitoring_Port)) != SOCK_OK)   // Server_Monitoring_Port 5062
        {
          return ret;	//	Try to TCP connect to the TCP server (destination)
        }
        Server_Monitoring_Req = FALSE;
     }
     else
     {
 	    if( (ret = connect(sn, Server_destip, Server_Alarm_Port)) != SOCK_OK)   // Server_Alarm_Port 5061
        {
          return ret;	//	Try to TCP connect to the TCP server (destination)
        } 
     }
     break;

  case SOCK_CLOSED:
	  close(sn);
      ch_status[sn] = 0;
       IP_Connect_Led(NO);   

#ifdef LOOPBACK_DEBUG
printf("%d:Socket closed\r\n",sn);
#endif
break;

  default:
     break;

}
return 1;

}

int IP_Send(unsigned char sn, uint8 * buf, uint16 len, char retry)
{
uint16 RSR_len;
int Snd_PktLength,Rcv_PktLength,tmp_retry_cnt;
int received_len,size,ret,sentsize;

       //printf("IP_Send=> getSn_RX_RSR(s)) =%d\r\n",getSn_RX_RSR(s) );
     if((size = getSn_RX_RSR(sn)) > 0) // Sn_RX_RSR: Socket n Received Size Register, Receiving data length
     {
		if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE; // DATA_BUF_SIZE means user defined buffer size (array)
		 ret= recv(sn, RX_BUF, size); // Data Receive process (H/W Rx socket buffer -> User's buffer)
		if(ret <= 0) return ret; // If the received data length <= 0, receive failed and process end                    
       }     
       sentsize = 0; 
       size = len;
   while(size != sentsize)
   {
			ret = send(sn, buf+sentsize, size-sentsize); // Data send process (User's buffer -> Destination through H/W Tx socket buffer)
			if(ret < 0) // Send Error occurred (sent data length < 0)
			{
                                    printf("Error Send size=%d\r\n",ret);
				close(sn); // socket close
				return ret;
			}
                            else
                            {
                                os_delay(2);
                                sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
                                printf("Success Send size=%d\r\n",ret);
                                continue;
                            }
                            printf(".");

       }
       return ret;

}

wireshark 8 번에서 부터 1…2…3…4…5 ~ 102까지 잘 진행 되다가 SOCK_CLOSED 로 갑자기 가 버립니다.
filter 적용하여 wireshark file 다시 첨부 했습니다.
capture 20170222-3.txt (23.8 KB)

위즈네트 방보현 연구원입니다.

별도의 명령없이 일방적으로 TCP가 close로 넘어가는 경우는 없습니다. 다음과 같은 경우에 Socket이 close 상태로 넘어갑니다.

  1. Server에서 끊었다. (서버가 끊었다면 FIN packet이 보입니다.)
  2. W5500에서 Close 명령을 내렸다.
  3. W5500에서 init 명령을 내렸다.

위에서 1번이 실행되었다면 당연히 wireshark에 로그가 남을 것입니다. 하지만 보내주신 데이터에는 해당 로그가 없으므로 2,3번이 유력한 것 같습니다.
2,3번이라면 사용 중이신 시스템(stm m3)에서 buffer overflow 등 기타 문제로 인해 reset이 되는 상황이 의심스럽습니다.

리셋이 아니라면 init 명령 내리는 부분이나 close 명령 내리는 부분을 debuging 해보시면 될 것 같습니다.

그래고 Printf()로 출력되어지는 로그를 주셔도 도움이 될 것 같습니다.

이상입니다.

Copyright © 2017 WIZnet Co., Ltd. All Rights Reserved.