初めてのネットワークプログラミング
環境
自分のホームに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 になっていないかチェックしてほしい。もしそうなら「不要なポート」は遮断されている可能性が高いので、会社とか家庭内の設定に直してうまくいくか試してみるとよい。