Cで書くTCPサーバの例（HEX dump付き）

こんにちは。

以前、仮想アプライアンスの検証のため、Cのソケットライブラリを使ってTCPサーバを作ったものがありました。ごくごく一般的なソケットプログラムで且つ、例によってツールのためあまりバッファサイズ等の考慮や定数定義もしきれていませんが、参考になる方がいれば幸いです。
ついでに、HEX/ASCIIダンプも出すようにしています。

# コードサンプル

```C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#define  BUFSIZE  2048
#define  OK          0
#define  NG         -1


/* display string HEX dump and ascii */
void dumpStr( char * pcStr )
{
    char sBuf[2048];
    int  iCnt = 0;
    int  iCnt2 = 0;
    char sDispBuf[80];

    memset( sBuf, 0x00, sizeof(sBuf) );
    if ( pcStr != NULL ) {
        strcpy( sBuf, pcStr ); 
    }
    memset( sDispBuf, ' ', sizeof(sDispBuf) );
    sDispBuf[sizeof(sDispBuf)-1] = 0x00;

    while ( 1 )
    {
        if ( sBuf[iCnt] == '\0' ) {
            printf( "%s\n", sDispBuf );
            break;
        }

        sprintf( &sDispBuf[iCnt2 * 3], "%2.02x ", sBuf[iCnt] );
        sDispBuf[(iCnt2*3)+3] = ' ';
        if ( 
          ( sBuf[iCnt] == '\r' ) || 
          ( sBuf[iCnt] == ' ' ) || 
          ( sBuf[iCnt] == '\t' ) || 
          ( sBuf[iCnt] == '\n' ) )
        {
            sDispBuf[iCnt2+50] = '.';
        } else {
            sDispBuf[iCnt2+50] = sBuf[iCnt];
        }
    
        iCnt ++;
        iCnt2 ++;

        if ( ( iCnt % 16 ) == 0 ) {
            printf( "%s\n", sDispBuf );
            memset( sDispBuf, ' ', sizeof(sDispBuf) );
            sDispBuf[sizeof(sDispBuf)-1] = 0x00;
            iCnt2 = 0;
        }
    }

    return;
}


/* main() */
int main( int ac, char *av[] )
{
    int iSoc;
    struct sockaddr_in stAddr;
    struct sockaddr_in stClient;
    socklen_t iLen;
    int iClSoc;
    struct timeval stTO;
    int iPort = 0;

    char sBuf [BUFSIZE];

    stTO.tv_sec = 1;
    stTO.tv_usec = 0;

    /* parameter check */
    if ( ac != 2 ) {
        perror( "you must set 1st parameter as port number." );
        return ( NG );
    } else {
        if ( ( iPort = atoi( av[1] ) ) == 0 ) {
            perror( "you must set 1st parameter as port number." );
            return ( NG );
        }
    }

    /* create listen socket */
    iSoc = socket( AF_INET, SOCK_STREAM, 0 );
    if ( iSoc < 0 )
    {
        perror( "socket()" );
        return ( NG );
    }

    stAddr.sin_family = AF_INET;
    stAddr.sin_port = htons( iPort );
    stAddr.sin_addr.s_addr = INADDR_ANY;

    /* set socket option */
    setsockopt( iSoc, SOL_SOCKET, SO_REUSEADDR, (const char *)&stTO, sizeof(struct timeval) );

    /* bind address to socket */
    if ( bind( iSoc, (struct sockaddr *)&stAddr, sizeof(stAddr) ) != 0 )
    {
        perror( "bind()" );
        return ( NG );
    }

    /* listen using socket */
    if ( listen( iSoc, 10 ) != 0 )
    {
        perror( "listen()" );
        return ( NG );
    }

    while ( 1 )
    {
        /* accept from client */
        iLen = sizeof( stClient );
        iClSoc = accept( iSoc, (struct sockaddr *)&stClient, &iLen );
        if ( iClSoc < 0 )
        {
            perror( "accept()" );
            break;
        }

        memset( sBuf, 0x00, sizeof(sBuf) );
        recv( iClSoc, sBuf, sizeof(sBuf), 0 );
#if 0
        printf( "%s", sBuf );
#else
        dumpStr( sBuf );
#endif

        send( iClSoc, sBuf, (int)strlen( sBuf ), 0 );

        close( iClSoc );
    }

    close( iSoc );

    return OK;
}
```

# 実行結果

PCのブラウザから、[IPアドレス:ポート番号]指定でアクセスしてみます。

```
$ ./tcps_command 12345
47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a   GET./.HTTP/1.1..             
48 6f 73 74 3a 20 31 32 37 2e 30 2e 30 2e 31 3a   Host:.127.0.0.1:             
31 32 33 34 35 0d 0a 43 6f 6e 6e 65 63 74 69 6f   12345..Connectio             
6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d 0a 55   n:.keep-alive..U             
70 67 72 61 64 65 2d 49 6e 73 65 63 75 72 65 2d   pgrade-Insecure-             
52 65 71 75 65 73 74 73 3a 20 31 0d 0a 55 73 65   Requests:.1..Use             
72 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61   r-Agent:.Mozilla             
2f 35 2e 30 20 28 4d 61 63 69 6e 74 6f 73 68 3b   /5.0.(Macintosh;             
20 49 6e 74 65 6c 20 4d 61 63 20 4f 53 20 58 20   .Intel.Mac.OS.X.   
(以下略)
```

左側にHEXダンプ、右側にASCIIで出力します。
不可視文字（タブ、スペース、復帰、改行）は'.'に置き換えて出すようにしています。

それでは。