TCP Server code

xiaoyi
2017-06-13
2017-06-20
  • xiaoyi - 2017-06-13

    I write the TCP server code on Codesys.
    But I meet some problem.

    1. SysSockRecv() always in 529. It mean Socket has been gracefully closed.
      The SysSockSend() work well .
    2. If I disconnec the client. The server will never connect to client again.
      Only power cycle , the server will works well again.

    Why ?

    PROGRAM TCP_SERVER
    VAR
    Address_server: SOCKADDRESS;
    AServer_size: UINT;
    i_udIPdescription_client: UDINT;
    Client_port: INT := 8000;
    AClient_size: UINT;
    i_udIPdescription: UDINT;
    Server_port: INT := 8001;
    PLC_IP: STRING := '192.168.1.10';
    ClientIP: STRING := '192.168.1.22';
    terminate: BOOL;
    tcp_state: INT;
    socketId: UDINT;
    dwValue: INT;
    bResult: SYSSOCKET.RTS_IEC_RESULT;
    SelectTimeOut: SYSSOCKET.SOCKET_TIMEVAL;
    SlaveSocketList: SYSSOCKET.SOCKET_FD_SET;
    MasterSocketList:SYSSOCKET.SOCKET_FD_SET;
    diSize: DINT;
    Socket_listen: SYSSOCKET.RTS_IEC_RESULT;
    TCPindex: INT;
    SocketHandle: RTS_IEC_HANDLE;
    TCPMax: RTS_IEC_HANDLE;
    SysSockRecv_result: RTS_IEC_RESULT;
    SysSocketSend_Result: RTS_IEC_RESULT;
    result: BOOL;
    Temp_SockerId: SYSSOCKET.RTS_IEC_HANDLE;
    Error_code: UDINT;
    Accept_ErrorCode: UDINT;
    ServerAddress_Des: UDINT;
    ClientAddress_Des: UDINT;
    Connect_number: SYSSOCKET.RTS_IEC_RESULT;
    receive_Data: array [ 1..512] of BYTE;
    send_data: array [1..512] of BYTE;
    END_VAR
    Address_server.sin_addr.ulAddr:=SysSockInetAddr(szIPAddress:=PLC_IP , pInAddr:= ADR(ServerAddress_Des));
    Address_server.sin_family:=SOCKET_AF_INET;
    Address_server.sin_port:=SysSockHtons(Server_port);
    AServer_size:= SIZEOF (Address_server);

    IF terminate=FALSE THEN
    CASE tcp_state OF
    0:
    socketId:=SysSockCreate(iAddressFamily:=SOCKET_AF_INET , diType:=SOCKET_STREAM , diProtocol:=SOCKET_IPPROTO_TCP , pResult:=ADR(Error_code));
    IF socketId <> -1 THEN
    dwValue := 1;
    (Set the option that we can reuse 'old' port addresses )
    SysSockSetOption(socketId, SOCKET_SOL, SOCKET_SO_REUSEADDR, ADR(dwValue), SIZEOF (dwValue));
    tcp_state := 10;
    END_IF

    10:
    bResult := SysSockBind(socketId, ADR(Address_server), AServer_size);
    IF UDINT_TO_BOOL(bResult) THEN
    tcp_state := 20;
    END_IF

    20:
    Socket_listen := SysSockListen(socketId, 255);
    IF Socket_listen=0 THEN
    MasterSocketList.fd_count := 1;
    MasterSocketList.fd_array[0] := socketId;
    tcp_state := 30;
    END_IF

    30:
    SlaveSocketList:=MasterSocketList;

    SelectTimeOut.tv_sec := 0;
    SelectTimeOut.tv_usec := 5000;

    Connect_number:=SysSockSelect(
    diWidth:=SOCKET_FD_SETSIZE ,
    pfdRead:=ADR(SlaveSocketList) ,
    pfdWrite:=0 ,
    pfdExcept:=0 ,
    ptvTimeout:= ADR(SelectTimeOut) ,
    pdiReady:=ADR(diSize ));
    //SysSockSelect(SOCKET_FD_SETSIZE, ADR(SlaveSocketList), 0, 0, ADR(SelectTimeOut));
    IF Connect_number > 0 THEN
    tcp_state := 50;
    TCPindex := 0;
    END_IF

    50:
    //SocketHandle := SlaveSocketList.fd_array[TCPindex];

    SocketHandle:=SysSockAccept(hSocket:=socketId , pSockAddr:=ADR(Address_server) , pdiSockAddrSize:=ADR(AServer_size) , pResult:=ADR(Accept_ErrorCode));
    //SysSockAccept(socketId, ADR(Address), ADR(address));
    IF SocketHandle <> -1 THEN
    TCPMax := SocketHandle;
    MasterSocketList.fd_array[MasterSocketList.fd_count] := SocketHandle;
    MasterSocketList.fd_count := MasterSocketList.fd_count + 1;
    END_IF
    tcp_state := 100;

    100:

    ( SysSockSend(socketId,ADR(send),SIZEOF(send),1);)
    SysSockRecv(
    hSocket:=socketId ,
    pbyBuffer:=ADR(receive_Data) ,
    diBufferSize:= SIZEOF(receive_Data),
    diFlags:=1,
    pResult:=ADR(SysSockRecv_result));

    tcp_state := 120;
    120:

    SysSockSend(
    hSocket:=SocketHandle ,
    pbyBuffer:=ADR(send_data) ,
    diBufferSize:=(write_len-1+6),
    diFlags:=1 ,
    pResult:=ADR(SysSocketSend_Result) );

    receive1[1]:=0;
    send_do:=FALSE;

    tcp_state := 100;

    END_CASE;
    END_IF;

    IF terminate = TRUE THEN ( close socket )
    SysSockClose(socketId);
    socketId := 0;
    tcp_state:=0;
    result := FALSE;

    END_IF

     
  • nothinrandom - 2017-06-20

    xiaoyi hat geschrieben:
    I write the TCP server code on Codesys.
    But I meet some problem.
    1. SysSockRecv() always in 529. It mean Socket has been gracefully closed.
    The SysSockSend() work well .
    2. If I disconnec the client. The server will never connect to client again.
    Only power cycle , the server will works well again.
    Why ?
    PROGRAM TCP_SERVER
    VAR
    Address_server: SOCKADDRESS;
    AServer_size: UINT;
    i_udIPdescription_client: UDINT;
    Client_port: INT := 8000;
    AClient_size: UINT;
    i_udIPdescription: UDINT;
    Server_port: INT := 8001;
    PLC_IP: STRING := '192.168.1.10';
    ClientIP: STRING := '192.168.1.22';
    terminate: BOOL;
    tcp_state: INT;
    socketId: UDINT;
    dwValue: INT;
    bResult: SYSSOCKET.RTS_IEC_RESULT;
    SelectTimeOut: SYSSOCKET.SOCKET_TIMEVAL;
    SlaveSocketList: SYSSOCKET.SOCKET_FD_SET;
    MasterSocketList:SYSSOCKET.SOCKET_FD_SET;
    diSize: DINT;
    Socket_listen: SYSSOCKET.RTS_IEC_RESULT;
    TCPindex: INT;
    SocketHandle: RTS_IEC_HANDLE;
    TCPMax: RTS_IEC_HANDLE;
    SysSockRecv_result: RTS_IEC_RESULT;
    SysSocketSend_Result: RTS_IEC_RESULT;
    result: BOOL;
    Temp_SockerId: SYSSOCKET.RTS_IEC_HANDLE;
    Error_code: UDINT;
    Accept_ErrorCode: UDINT;
    ServerAddress_Des: UDINT;
    ClientAddress_Des: UDINT;
    Connect_number: SYSSOCKET.RTS_IEC_RESULT;
    receive_Data: array [ 1..512] of BYTE;
    send_data: array [1..512] of BYTE;
    END_VAR
    Address_server.sin_addr.ulAddr:=SysSockInetAddr(szIPAddress:=PLC_IP , pInAddr:= ADR(ServerAddress_Des));
    Address_server.sin_family:=SOCKET_AF_INET;
    Address_server.sin_port:=SysSockHtons(Server_port);
    AServer_size:= SIZEOF (Address_server);
    IF terminate=FALSE THEN
    CASE tcp_state OF
    0:
    socketId:=SysSockCreate(iAddressFamily:=SOCKET_AF_INET , diType:=SOCKET_STREAM , diProtocol:=SOCKET_IPPROTO_TCP , pResult:=ADR(Error_code));
    IF socketId <> -1 THEN
    dwValue := 1;
    (Set the option that we can reuse 'old' port addresses )
    SysSockSetOption(socketId, SOCKET_SOL, SOCKET_SO_REUSEADDR, ADR(dwValue), SIZEOF (dwValue));
    tcp_state := 10;
    END_IF
    10:
    bResult := SysSockBind(socketId, ADR(Address_server), AServer_size);
    IF UDINT_TO_BOOL(bResult) THEN
    tcp_state := 20;
    END_IF
    20:
    Socket_listen := SysSockListen(socketId, 255);
    IF Socket_listen=0 THEN
    MasterSocketList.fd_count := 1;
    MasterSocketList.fd_array[0] := socketId;
    tcp_state := 30;
    END_IF
    30:
    SlaveSocketList:=MasterSocketList;
    SelectTimeOut.tv_sec := 0;
    SelectTimeOut.tv_usec := 5000;
    Connect_number:=SysSockSelect(
    diWidth:=SOCKET_FD_SETSIZE ,
    pfdRead:=ADR(SlaveSocketList) ,
    pfdWrite:=0 ,
    pfdExcept:=0 ,
    ptvTimeout:= ADR(SelectTimeOut) ,
    pdiReady:=ADR(diSize ));
    //SysSockSelect(SOCKET_FD_SETSIZE, ADR(SlaveSocketList), 0, 0, ADR(SelectTimeOut));
    IF Connect_number > 0 THEN
    tcp_state := 50;
    TCPindex := 0;
    END_IF
    50:
    //SocketHandle := SlaveSocketList.fd_array[TCPindex];
    SocketHandle:=SysSockAccept(hSocket:=socketId , pSockAddr:=ADR(Address_server) , pdiSockAddrSize:=ADR(AServer_size) , pResult:=ADR(Accept_ErrorCode));
    //SysSockAccept(socketId, ADR(Address), ADR(address));
    IF SocketHandle <> -1 THEN
    TCPMax := SocketHandle;
    MasterSocketList.fd_array[MasterSocketList.fd_count] := SocketHandle;
    MasterSocketList.fd_count := MasterSocketList.fd_count + 1;
    END_IF
    tcp_state := 100;
    100:
    ( SysSockSend(socketId,ADR(send),SIZEOF(send),1);)
    SysSockRecv(
    hSocket:=socketId ,
    pbyBuffer:=ADR(receive_Data) ,
    diBufferSize:= SIZEOF(receive_Data),
    diFlags:=1,
    pResult:=ADR(SysSockRecv_result));
    tcp_state := 120;
    120:
    SysSockSend(
    hSocket:=SocketHandle ,
    pbyBuffer:=ADR(send_data) ,
    diBufferSize:=(write_len-1+6),
    diFlags:=1 ,
    pResult:=ADR(SysSocketSend_Result) );

    receive1[1]:=0;
    send_do:=FALSE;
    tcp_state := 100;
    END_CASE;
    END_IF;
    IF terminate = TRUE THEN ( close socket )
    SysSockClose(socketId);
    socketId := 0;
    tcp_state:=0;
    result := FALSE;
    END_IF

    I would highly recommend you install the Network library instead. Then use these function blocks which will make your life much easier.:

    VAR
    // =======================================
    // set up server
    // =======================================
    _TCPServer : NBS.TCP_Server;
    _TCPServer_ipAddr: NBS.IP_ADDR;
    _TCPServer_uiPort: UINT:= uiPort;
    _TCPServer_hServer : CAA.HANDLE; // server handle
    _sServerIP : STRING(15):='192.168.1.100'; ( this device's server IP address )
    _uiPort : UINT:= 10000;
    _TCPConnection : NBS.TCP_Connection; // TCP connection instances
    _TCPConnection_hConnection: CAA.HANDLE; // handle of client connections
    _TCPWrite : NBS.TCP_Write; // TCP write
    _TCPRead : NBS.TCP_Read; // TCP read
    _sTCPSendData: STRING:= 'Hello World';
    _sTCPReadData: STRING(1000); //receive up to 1000 chars if needed
    END_VAR

    PROGRAM:
    _TCPServer_ipAddr.sAddr := _sServerIP; //set IP address
    _TCPServer(
    xEnable:= , // manually toggle for testing
    xDone=> ,
    xBusy=> ,
    xError=> ,
    ipAddr:= _TCPServer_ipAddr,
    uiPort:= _uiPort,
    eError=> ,
    hServer=> _TCPServer_hServer);

    // set TCP connection
    _TCPConnection(
    xEnable:= _TCPServer.xBusy AND NOT(_TCPConnection.xDone), //when server is ready
    xDone=> , // client manually disconnected
    xBusy=> ,
    xError=> ,
    hServer:= _TCPServer.hServer, // point all connections back to the same server
    eError=> ,
    xActive=> ,
    hConnection=> _TCPConnection_hConnection);

    // only execute on active connections
    IF(_TCPConnection.xActive) THEN
    // write when connection is ready
    _TCPWrite(
    xExecute:= _TCPWriteEn, //manually enable for testing
    udiTimeOut:= 600000, //in microseconds => 600ms
    xDone=> ,
    xBusy=> ,
    xError=> ,
    hConnection := _TCPConnection_hConnection,
    szSize := INT_TO_UINT(LEN(_sTCPSendData)), // write length only
    pData := ADR(_sTCPSendData),
    eError=> );
    //reset write enable
    IF(_TCPWrite.xDone) THEN
    _TCPWriteEn:= FALSE;
    END_IF
    // read when connection is ready
    _TCPRead(
    xEnable:= TRUE,
    xDone=> ,
    xBusy=> ,
    xError=> ,
    hConnection:= _TCPConnection_hConnection,
    szSize:= SIZEOF(_sTCPReadData),
    pData:= ADR(_sTCPReadData),
    eError=> ,
    xReady=> ,
    szCount=> );
    ELSE
    // no connection made
    _TCPRead.xEnable:= FALSE;
    _TCPWrite.xExecute:= FALSE;
    END_IF

     

Log in to post a comment.