#include #include #include #include #include #include #include #include #include #include #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; }