$ gcc socket_sample.c -o socket_sampleターミナルを二つ立ち上げて、一つで
$ ./socket_sample 8011として、サーバを起動します。(8011はポート番号で、好きな番号を指定してください)
$ ./socket_sample 8011 127.0.0.1として、クライアントを起動してサーバに接続します。 8011 は先ほどと同じポート番号を指定してください。 127.0.0.1 というところは、サーバの IP アドレスを指定します。 サーバとクライアントを同じマシンで立ち上げる場合は、 127.0.0.1 で大丈夫です。
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <assert.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netdb.h>#define LEN 1024 * 1024 * 4 #define TRIALS 100
#define MY_RCVBUF 1024 * 10
/***************************************************/
/* basic network functions come here: */
/* サーバ・クライアント のモード*/ enum { MODE_SERVER = 10, MODE_CLIENT = 11, };
/* コマンドラインからの設定項目 */ struct config { int mode; int port; char *hostname; };
void error_exit(char cp){ / エラーを出力して終了 */ perror(cp); exit(1); }
double get_dtime(void){ /* 時間を double 型で返す */ struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return (double)(tv.tv_sec) + (double)(tv.tv_usec) * 0.001 * 0.001; }
void usage(char cmd){ / 使い方を出力 */ printf("Usage: %s [port] ( [server_name] )\n", cmd); printf(" example: %s 5011 ... for server\n", cmd); printf(" %s 5011 10.0.127.13 ... for client\n", cmd); exit(1); }
void read_config(struct config *config, int args, char *argv){ / コマンドラインから設定を読み込む */ assert(config != NULL);
if(args == 2){ // only port is specified -> server mode config->mode = MODE_SERVER;
config->port = atoi(argv[1]); } else if(args == 3){ // only port is specified -> server mode config->mode = MODE_CLIENT; config->port = atoi(argv[1]); config->hostname = argv[2]; } else { usage(argv[0]); } }/***************************************************/
int prepare_server_socket(int port){ /* サーバソケットの準備 */ int ret; int sock; struct sockaddr_in sa;
/* ソケット生成 */ sock = socket(PF_INET, SOCK_STREAM, 0);
/* bind: ソケットをポートに割り当てる*/ sa.sin_family = AF_INET; sa.sin_addr.s_addr = INADDR_ANY; sa.sin_port = htons(port); ret = bind(sock, (struct sockaddr*)&sa, sizeof(sa)); if(ret == -1) error_exit("bind");
/* listen: 待ち受けを始める */ ret = listen(sock, 5); if(ret == -1) error_exit("listen"); return sock; }
int close_server_socket(int server_sock){ /* ソケットのクローズ */ close(server_sock); }
int do_accept(int server_sock){ /* 接続を受け付け、ソケットを返す */ int sock = accept(server_sock, NULL, NULL); if(sock == -1) error_exit("accpet"); return sock; }
void close_sock(int sock){ /* ソケットを閉じる */ close(sock); }
int do_connect(char hostaddr, int port){ / サーバに connect する。/ / ホスト名ではなく、IP アドレスを指定してください。*/ int ret; int sock; struct sockaddr_in sa;
sock = socket(PF_INET, SOCK_STREAM, 0); sa.sin_family = AF_INET; printf("connect to %s\n", hostaddr); inet_aton(hostaddr, &(sa.sin_addr)); sa.sin_port = htons(port);
ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa)); if(ret == -1) error_exit("connect"); return sock; }
void do_send(int sock, int size, char buf){ / size の量のデータを送る / / WAITALL を指定することで、指定した量送られるまで関数が返らない */ int ret = send(sock, buf, size, MSG_WAITALL); if(ret != size) error_exit("Send interrupted");
}void do_recv(int sock, int size, char buf){ / size の量のデータを受信する / / WAITALL を指定することで、指定した量受け取るまで関数が返らない */ int ret = recv(sock, buf, size, MSG_WAITALL); if(ret != size) error_exit("Recv interrupted"); }
/* 受信バッファの値を設定 void set_rcvbuf(int sock, int bufsize){
int ret; int i; getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, 4); printf("original RCVBUF: %d\n", i);
ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)); if(ret < 0) error_exit("setsockopt"); } */
/***************************************************/
void client_core(int sock){ int i; char buf[LEN]; double d0, d1, bandwidth;
// set_rcvbuf(sock, MY_RCVBUF);
for(i = 0; i < TRIALS; i++){ d0 = get_dtime(); do_recv(sock, LEN, buf); d1 = get_dtime(); bandwidth = (double)LEN * 8 / (d1-d0) / 1000 / 1000; printf("client: %d, bandwidth: %f Mbps\n", i, bandwidth); } }
void server_core(int sock){ int i; char buf[LEN];
for(i = 0; i < TRIALS; i++){ do_send(sock, LEN, buf); printf("server: %d\n", i); } }
/***************************************************/
int server(struct config cfg){ / 何回でも接続を受け付け、データを送信する */ int server_sock = prepare_server_socket(cfg->port); for(;;){ int sock = do_accept(server_sock); server_core(sock); close_sock(sock); } close_server_sock(server_sock); }
int client(struct config cfg){ / サーバに一回だけ接続し、データを受信し、終了する。*/ int sock = do_connect(cfg->hostname, cfg->port); client_core(sock); close_sock(sock); }
/***************************************************/
int main(int args, char **argv){ int mode; struct config cfg;
read_config(&cfg, args, argv);
switch(cfg.mode){ case MODE_SERVER: server(&cfg); break;
case MODE_CLIENT: client(&cfg); break;
default: assert(0); }
return 0; }