メモ - ソケット通信について
ホーム > メモ > ソケット通信について
カウンターです。

2002.08.11

・ソケット通信について。

ソケット通信をするプログラム例です。あるサイトのプログラムをダウンロードして、少しカスタマイズした物を記載します。

サーバ側
/*                                              */
/* コネクション型のサーバプログラム (hellosv.c) */
/*   Usage: hellosv host_name &                 */
/*                                              */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PROT_NO 5001

static  char    mesg[] = "Hello world.";

static  struct sockaddr_in      sv_addr;        /* サーバアドレス */
static  struct sockaddr_in      cl_addr;        /* クライアントアドレス */
static  struct hostent          *sv_ip;         /* サーバIPアドレス */

static  int     sid1;           /* デーモンソケット識別子 */
static  int     sid2;           /* 子プロセスソケット識別子 */
static  int     cl_size;        /* クライアントアドレスサイズ */

/* サーバメイン */
main(argc, argv)
int     argc;
char    *argv[];        /* argv[1]:サーバホスト名 */
{
        int     rtn;    /* 返却値 */

        /* 第一引数が省略されている場合はエラーとする。 */
        if(&argv[1][0] == 0x00)
        {
                perror("argv[1]");
                exit(1);
        }

        /* コネクション型ソケットの作成 (socket) */
        sid1 = socket(AF_INET, SOCK_STREAM, 0);
        if (sid1 < 0) {
                perror("sv:socket");
                goto err;
        }

        /* サーバのIPアドレスを取得 */
        sv_ip = gethostbyname(argv[1]);
        if (sv_ip == NULL) {
                perror("sv:gethostbyname");
                goto err;
        }

        /* ソケットに名前を付加 (bind) */
        bzero((char *)&sv_addr, sizeof(sv_addr));
        sv_addr.sin_family = AF_INET;
        sv_addr.sin_port = htons(PROT_NO);
        memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr,
                sv_ip->h_length);
        rtn = bind(sid1, &sv_addr, sizeof(sv_addr));
        if (rtn < 0) {
                perror("sv:bind");
                goto err;
        }

        /* クライアントからの接続要求の受付 (listen) */
        rtn = listen(sid1, 5);
        if (rtn == -1) {
                perror("sv:listen");
                goto err;
        }

        while (1) {
                /* クライアントからの接続要求の受信 (accept) */
                cl_size = sizeof(cl_addr);
                sid2 = accept(sid1, &cl_addr, &cl_size);
                if (sid2 < 0) {
                        perror("sv:accept");
                        goto err;
                }

                /* メッセージ通信処理 (send/recv) */
                rtn = send(sid2, mesg, sizeof(mesg), 0);
                if (rtn < 0) perror("sv:send");

                /* ソケットの開放 (shutdown,close) */
                rtn = shutdown(sid2, 2);
                if (rtn < 0) perror("sv:shutdown");
                close(sid2);
        }

        err:
        /* ソケットの開放 (close) */
        close(sid1);
        exit(0);
}

クライアント側
/*                                                  */
/* コネクション型クライアントプログラム (hellocl.c) */
/*   Usage: hellocl host_name                       */
/*                                                  */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PROT_NO 5001    /* ポート番号 */
#define BUF_MAX 64      /* 通信バッファサイズ */

static  struct sockaddr_in      sv_addr;        /* サーバアドレス */
static  struct hostent          *sv_ip;         /* サーバIPアドレス */

static  int     sid;            /* ソケット識別子 */
static  char    buf[BUF_MAX];   /* 通信バッファ */

/* クライアントメイン */
main(argc, argv)
int     argc;
char    *argv[];        /* argv[1]:サーバホスト名 */
{
        int     rtn;            /* 返却値 */

        /* 第一引数が省略されている場合はエラーとする。 */
        if(&argv[1][0] == 0x00)
        {
                perror("argv[1]");
                exit(1);
        }

        /* コネクション型ソケットの作成 (socket) */
        sid = socket(AF_INET, SOCK_STREAM, 0);
        if (sid < 0) {
                perror("cl:socket");
                exit(1);
        }

        /* サーバのIPアドレスを取得 */
        sv_ip = gethostbyname(argv[1]);
        if (sv_ip == NULL) {
                perror("cl:gethostbyname");
                exit(1);
        }

        /* ソケットの接続要求 (connect) */
        bzero((char *)&sv_addr, sizeof(sv_addr));
        sv_addr.sin_family = AF_INET;
        sv_addr.sin_port = htons(PROT_NO);
        memcpy((char *)&sv_addr.sin_addr, (char *)sv_ip->h_addr,
                sv_ip->h_length);
        rtn = connect(sid, &sv_addr, sizeof(sv_addr));
        if (rtn < 0) {
                perror("cl:connect");
                close(sid);
                exit(1);
        }

        /* メッセージ通信処理 (send/recv) */
        rtn = recv(sid, buf, BUF_MAX, 0);
        if (rtn < 0) perror("cl:recv");
        printf("%s\n", buf);

        /* ソケットの開放 (shutdown/close) */
        rtn = shutdown(sid, 2);
        if (rtn < 0) perror("cl:shutdown");
        close(sid);
        exit(0);
}

メイクファイル
all:	hellosv hellocl

clean:
	rm -f hellosv hellocl *.o

hellosv:	hellosv.c
	cc -o hellosv hellosv.c -lnsl 

hellocl:	hellocl.c
	cc -o hellocl hellocl.c -lnsl

動作確認 TurboLinux6.1 Server

ご参考までに・・・ サーバプログラム | クライアントプログラム | メイクファイル

まぁ、goto文があったりで、あまり良くないプログラムなので、構造や関数の使い方だけを参考にした方が良いかと思います。

戻る
http://kank.o.oo7.jp/2016/memo/20020811.html

初版:2003.02.23
更新:2005.6.27(一部改良)
更新:2013.7.2(リニューアル)
更新:2016.8.17(リニューアル)