サンプル集  >  LinuxC  >  通信(クライアント側)
通信(クライアント側)
2013/11/25

>> 通信(サーバー側) からの続き

通信プログラムのクライアント側です。

◆環境
OS Linux obsax3 3.0.6 #1 SMP Fri Nov 16 11:53:45 JST 2012 armv7l GNU/Linux
gcc 4.4.5 (Debian 4.4.5-8)

サーバーへ接続後、メッセージの受信を wait と don't wait のどちらかを選択できるようにしました。 ログ出力関数 outputLog はサーバー側のプログラムを使いました。

LC112Server.c
  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <unistd.h>
#include "outputLog.h"
#include "errno.h"

int recvProc ( int dstSocket, int flags );

int main()
{
    outputLog( "CL""LC113Client START\n" );

    char pcIP[15+1];     // IPアドレス
    int  iRet;

    strcpy( pcIP,   "127.0.0.1" );

    // IP アドレス、ソケット、sockaddr_in 構造体
    int dstSocket;
    struct sockaddr_in dstAddr;
    memset( &dstAddr, 0x00, sizeof( dstAddr ) );

    // struct sockaddr_in addr;
    struct hostent *hp;

    // sockaddr_in 構造体のセット
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_port   = htons( 9876 );

    hp = gethostbyname( pcIP );
    if ( hp == NULL )
    {
        switch( h_errno )
        {
        case HOST_NOT_FOUND:
            outputLog( "CL""ERROR HOST_NOT_FOUND:%s<",  pcIP );
            break;
        default:
            outputLog( "CL""ERROR h_errno:%d", h_errno );
            break;
        }
        return( -1 );
    }
    bcopy( hp->h_addr, &dstAddr.sin_addr, hp->h_length );

    // ソケットの生成
    dstSocket = socket( AF_INET, SOCK_STREAM, 0 );

    // 接続
    iRet = connect( dstSocket
                  , ( struct sockaddr* )&dstAddr
                  , sizeof( dstAddr )
                  );
    if ( iRet != 0 )
    {
        perror( "connect" );
        return( -2 );
    }
    outputLog( "CL""connect OK\n" );

    int iProc = 1;
    while( iProc )
    {
        int iInpt;
        outputLog( "CL""----------------------------------\n" );
        outputLog( "CL""(1) recv message(wait)\n" );
        outputLog( "CL""(2) recv message(don't wait)\n" );
        outputLog( "CL""(9) end\n" );
        outputLog( "CL""input number: " );
        scanf( "%d", &iInpt );

        switch( iInpt )
        {
        case 1:
            // 受信(wait)
            recvProc( dstSocket, 0 );
            break;
        case 2:
            // 受信(don't wait)
            recvProc( dstSocket, MSG_DONTWAIT );
            break;
        case 9:
            outputLog( "CL""終了します。\n" );
            iProc = 0;
            break;
        default:
            outputLog( "CL""番号を選んで下さい。\n" );
            break;
        }
    }

    close( dstSocket );

    outputLog( "CL""LC113Client END\n" );
    return( 0 );
}

int recvProc( int dstSocket, int flags )
{
    char pcBuf[256];
    int iRecvNum = 0;

    memset( pcBuf, 0x00, sizeof( pcBuf ) );
    iRecvNum = recv( dstSocket, pcBuf, sizeof( pcBuf ), flags );
    if ( iRecvNum < 0 )
    {
        printf( "ret=[%d] errno=[%d] msg=[%s]\n"
              , iRecvNum
              , errno
              , strerror( errno )
              );
        return( -1 );
    }

    pcBuf[iRecvNum] = 0x00;
    outputLog( "CL"
             , "recv=[%s] len=[%d] errno=[%d] msg=[%s]\n"
             , pcBuf
             , iRecvNum
             , errno
             , strerror( errno )
             );

    return( 0 );
}

メイクファイルです。

makefile
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
# 2013/11/25 (c) ymlib.com
TARGET = LC113Client
OBJS = LC113Client.o outputLog.o
CC = /usr/bin/gcc

$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS)
.SUFFIXES: .c.o
.c.o:
$(CC) -Wall -c $< -g

clean:
rm -f $(TARGET) $(OBJS)

まずはサーバー側のプログラムを起動します。

# ./LC112Server
13:12:18 SV LC112Server START
13:12:18 SV 接続を待っています

サーバー側が接続待ちになりました。

別のターミナルを開き、クライアント側を起動します。

# ./LC113Client
13:13:06 CL LC113Client START
13:13:06 CL connect OK
13:13:06 CL ----------------------------------
13:13:06 CL (1) recv message(wait)
13:13:06 CL (2) recv message(don't wait)
13:13:06 CL (9) end
13:13:06 CL input number:

サーバーに接続し処理番号の入力待ちになりました。 サーバー側も接続を受け付け、処理番号の入力待ちになりました。

13:13:06 SV accept OK
13:13:06 SV ----------------------------------
13:13:06 SV (1) send messase
13:13:06 SV (9) end
13:13:06 SV input number:

サーバー側でメッセージを送ります。1 を入力しEnterを押します。

13:13:06 SV input number: 1
13:15:17 SV send OK!!
13:15:17 SV ----------------------------------
13:15:17 SV (1) send messase
13:15:17 SV (9) end
13:15:17 SV input number:

sendに成功し、次の処理番号入力待ちになりました。

クライアント側で受信(wait)してみます。 クライアント側で 1を入力しEnterを押します。

13:13:06 CL input number: 1
13:16:01 CL recv=[send server!!] len=[13] errno=[0] msg=[Success]
13:16:01 CL ----------------------------------
13:16:01 CL (1) recv message(wait)
13:16:01 CL (2) recv message(don't wait)
13:16:01 CL (9) end
13:16:01 CL input number:

メッセージを正しく受信し、次の処理番号入力待ちになりました。 9 を入力しクライアント側を終了します。

13:16:01 CL input number: 9
13:17:07 CL 終了します。
13:17:07 CL LC113Client END

サーバー側でも 9 を入力し終了します。

13:17:50 SV 終了します。
13:17:50 SV LC112Server END

切断検知のテスト

クライアントが接続後、サーバーが切断(close)した場合どうなるかテストします。

@接続確立後、サーバーがclose

まずはサーバーを起動し、続いてクライアントを起動し両方とも処理番号入力待ちにします。 この状態でサーバーを 9 で終了させます。

13:36:40 SV input number: 9
13:36:42 SV 終了します。
13:36:42 SV LC112Server END

サーバー終了後、クライアント側は 1 でメッセージの受信を試みたところ以下の結果になりました。

13:36:40 CL input number: 1
13:36:45 CL recv=[] len=[0] errno=[0] msg=[Success]
13:36:45 CL ----------------------------------
13:36:45 CL (1) recv message(wait)
13:36:45 CL (2) recv message(don't wait)
13:36:45 CL (9) end
13:36:45 CL input number:

recvが正常終了しています。errno は 0。メッセージも Success となっています。 再度、1 を入力して受信してみましたが結果は同じでした。2 の don't wait で受信しても結果は同じでした。

A接続確立後、クライアント側が受信待ち状態のときにサーバーがclose

まずはサーバーを起動し、続いてクライアントを起動し両方とも処理番号入力待ちにします。 この状態でクライアントを 1 で受信待ち状態にします。

13:43:33 CL LC113Client START
13:43:33 CL connect OK
13:43:33 CL ----------------------------------
13:43:33 CL (1) recv message(wait)
13:43:33 CL (2) recv message(don't wait)
13:43:33 CL (9) end
13:43:33 CL input number: 1

この状態でサーバーを 9 で終了させます。

13:43:33 SV input number: 9
13:44:44 SV 終了します。
13:44:44 SV LC112Server END

サーバーが終了すると、クライアントは空メッセージを受信し、次の処理番号入力待ちになりました。

13:44:44 CL recv=[] len=[0] errno=[0] msg=[Success]
13:44:44 CL ----------------------------------
13:44:44 CL (1) recv message(wait)
13:44:44 CL (2) recv message(don't wait)
13:44:44 CL (9) end
13:44:44 CL input number:

再度、1 を入力して受信してみましたが結果は同じでした。2 の don't wait で受信しても結果は同じでした。

B接続確立後、クライアント側が受信待ち状態のときにサーバーを強制終了(kill)

まずはサーバーを起動し、続いてクライアントを起動し両方とも処理番号入力待ちにします。 この状態でクライアントを 1 で受信待ち状態にします。 その状態でサーバープロセスを kill します。

14:12:40 SV LC112Server START
14:12:40 SV 接続を待っています
14:12:45 SV accept OK
14:12:45 SV ----------------------------------
14:12:45 SV (1) send messase
14:12:45 SV (9) end
14:12:45 SV input number: Killed

処理番号入力待ちのカーソルが表示されていた位置に「Killed」と表示され終了しました。 クライアント側は今までと同じく、空メッセージを受信し、次の処理番号入力待ちになりました。

14:13:12 CL recv=[] len=[0] errno=[0] msg=[Success]
14:13:12 CL ----------------------------------
14:13:12 CL (1) recv message(wait)
14:13:12 CL (2) recv message(don't wait)
14:13:12 CL (9) end
14:13:12 CL input number:

don't wait でも結果は同じでした。

メッセージが無い時の受信(don't wait)

メッセージが無い時に受信(wait)を実行すると、メッセージが書き込まれるまで止まります。 メッセージが無い時に受信(don't wait)を実行すると次のエラーが発生します。

ret=[-1] errno=[11] msg=[Resource temporarily unavailable]

wait と don't wait の違い

受信のwaitとdon't waitで次のように動作が違いました。

メッセージ接続waitdon't wait
有りOK読み込む読み込む
Close読み込む読み込む
無しOKメッセージが書き込まれるまで待つ(止まる)返り値が -1 になり errno に 11 (EAGAIN) が設定される。
Close返り値が 0 になり空メッセージを受信する。返り値が 0 になり空メッセージを受信する。

上記の結果より don't wait で受信して、返り値が 0 の場合、接続が切断されたと判断しても良さそうです。

>> 続き

▲ PageTop  ■ Home


Copyright (C) 2013 ymlib.com