トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

OneToOne

初めてのネットワークプログラミング

  環境

自分のホームにsocというディレクトリを用意しよう。さらに、その下にsoc/1-1/というディレクトリが必要で、ここで以下のすべての作業が行われる。

  参考文献

  • UNIXネットワークベストプログラミング、雪田修一、技術評論社

  作業環境

  • Cygwinのホームディレクトリ以下に
ホーム/soc/

あるいは

ホーム/soc/1-1/

のようなディレクトリを作成し、そこで作業を行う。

  Cygwin Bashのコマンド

コマンド名 意味 使用例
pwd print working directory 現在のディレクトリの表示 pwd
cd change directory ディレクトリの移動 cd 行先のディレクトリ
ls list 現在のディレクトリのファイル一覧 ls
mkdir make directory ディレクトリの作成 mkdir ディレクトリ名
rm remove ファイルの削除 rm ファイル名
rmdir remove directory ディレクトリの削除 rmdir ディレクトリ名
mv move ファイルの移動あるいは名前の変更 mv 旧ファイル名 新ファイル名

  サンプルプログラム

Headerファイル

/*********************************************/
/*       File name:  one2one.h               */
/*    Project name:  socket/1-1              */
/*      Month/Year:  Jan/2003                */
/*          Author:  Shuichi YUKITA          */
/*********************************************/

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define  PORT  50000
#define  HOSTNAME_LENGTH 20
#define  MSG_BUF_LEN 512

extern char * chop_newline(char *, int);

サーバ 待ち受け側

/*********************************************/
/*       File name:  server.c                */
/*    Project name:  socket/1-1              */
/*      Month/Year:  Jan/2003                */
/*          Author:  Shuichi YUKITA          */
/*********************************************/

#include "one2one.h"

main()
{
  struct  sockaddr_in   me;
  int  s,snew;
  char  send_buf[MSG_BUF_LEN];
  char  recv_buf[MSG_BUF_LEN];
  int count;

  memset((char *)&me, 0, sizeof(me));
  me.sin_family = AF_INET;
  me.sin_addr.s_addr = htonl(INADDR_ANY);
  me.sin_port = htons(PORT);

  if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0 )	{
    perror("socket");
    exit(1);
  }

  if (bind(s,(struct sockaddr *)&me,sizeof(me)) == -1){
    perror("bind");
    exit(1);
  }

  listen(s,1);
  fprintf(stderr,"successfully bound, now waiting.\n");
  snew = accept(s,NULL,NULL);
  close(s);

  do	{
    printf("input: ");
    fgets(send_buf,MSG_BUF_LEN,stdin);
    /*    chop_newline(send_buf,MSG_BUF_LEN);*/
    write(snew,send_buf,strlen(send_buf));
    count = read(snew,recv_buf,MSG_BUF_LEN);
    recv_buf[count] = '\0';
    printf("client: %s",recv_buf);
  }
  while (strncmp(recv_buf,"quit",4) != 0);

  close(snew);
}

クライアント 接続を要求する側

/*********************************************/
/*       File name:  client.c                */
/*    Project name:  socket/1-1              */
/*      Month/Year:  Jan/2003                */
/*          Author:  Shuichi YUKITA          */
/*********************************************/

#include "one2one.h"

main()
{
  struct  hostent  *server_ent;
  struct  sockaddr_in  server;
  int s;  /* descriptor for socket */
  char  send_buf[MSG_BUF_LEN];
  char  recv_buf[MSG_BUF_LEN];
  char  hostname[HOSTNAME_LENGTH];
  int   count;

  printf("input  server's  hostname: ");
  fgets(hostname, HOSTNAME_LENGTH, stdin);
  chop_newline(hostname, HOSTNAME_LENGTH);

  if((server_ent = gethostbyname(hostname)) == NULL){
    perror("gethostbyname");
    exit(1);
  }

  memset((char *)&server,0,sizeof(server));
  server.sin_family = AF_INET;
  server.sin_port = htons(PORT);
  memcpy((char *)&server.sin_addr, server_ent->h_addr, 
	 server_ent->h_length);

  if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0){
    perror("socket");
    exit(1);
  }

  if (connect(s,(struct sockaddr *)&server,sizeof(server)) == -1){
    perror("connect");
    exit(1);
  }
  fprintf(stderr,"connected.\n");

  do   {
    count = read(s,recv_buf,MSG_BUF_LEN);
    recv_buf[count] = '\0';
    printf("server: %s",recv_buf);
    printf("input: ");
    fgets(send_buf,MSG_BUF_LEN,stdin);
    /*    chop_newline(send_buf,MSG_BUF_LEN);*/
    write(s,send_buf,strlen(send_buf));
  }
  while( strncmp(send_buf,"quit",4) != 0 );

  close(s);
}

chop_newline.c

/*********************************************/
/*       File name:  chop_newline.c          */
/*    Project name:  socket/1-1              */
/*      Month/Year:  Jan/2003                */
/*          Author:  Shuichi YUKITA          */
/*********************************************/

#include "one2one.h"

char * chop_newline(char *str, int len){
  int n = strlen(str);

  if(n < len && str[n-1] == '\n'){
    str[n-1] = '\0';
  }
  return str;
}

  コンパイル

Makefileを用意する。ファイル名はMakefileとする。このMakefileができたら、コマンドラインから

make

としてやれば実行ファイルができあがる。

#*********************************************/
#*       File name:  Makefile                */
#*    Project name:  socket/1-1              */
#*      Month/Year:  Jan/2003                */
#*          Author:  Shuichi YUKITA          */
#*********************************************/
#
#  "root.o" target is implicitly built by
#  $(COMPILE.c) -o root.o root.c

RM=rm -f

all:	s c

s:	server.o chop_newline.o
	$(LINK.c)  -o s  server.o chop_newline.o

c:	client.o chop_newline.o
	$(LINK.c)  -o c  client.o chop_newline.o

server.o:	server.c one2one.h

client.o:	client.c one2one.h

clean:
	$(RM) s c *.o *~

  実行

自分のコンピュータ内でプロセス間通信

Cygwinのウィンドウでmakeコマンドを実行すると

s.exe と c.exe

というファイルが生成する。

実行は、まず、一つのウィンドウでserverを起動する。

./s

次に、他のウィンドウでclientを起動する。

./c

接続先ホスト名を聞かれたら、

localhost

を指定する。

他のコンピュータと通信

  • 途中にファイアーウォールが無いことが前提。実験したいときは管理者に相談すること。
  • クライアント側は相手のIPアドレスを接続先のホスト名に指定する。
  • サーバ側のマシンのIPアドレスはオフラインで教えてあげよう。
  • IPアドレスはWindows OSの場合は ipconfig コマンドで確認できる。UNIX系OSやMacを使っている人には説明は不要ですね。
  • 同じLAN上でうまくつながらないときは、ネットワークの種類が public network になっていないかチェックしてほしい。もしそうなら「不要なポート」は遮断されている可能性が高いので、会社とか家庭内の設定に直してうまくいくか試してみるとよい。