-
Notifications
You must be signed in to change notification settings - Fork 0
/
ft_client.c
220 lines (188 loc) · 7.02 KB
/
ft_client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include "error_handler.h"
#define BUFF_SIZE 64 // バッファのサイズ
// プロトタイプ宣言
int get_file_size(char *file_name);
int main(int argc, char *argv[])
{
// 時間を格納する構造体を宣言
struct timeval start_time;
struct timeval end_time;
// サーバのアドレスとポート番号
// 127.0.0.1は、ループバックアドレス
// 他のPCと通信する場合は、当該PCのIPアドレスに変更する。
// char *serv_ip = "172.18.85.234";
char *serv_ip = "127.0.0.1";
in_port_t serv_port = 50000;
// 受信用バッファ:戻り値の保存用に使う変数
char buff[BUFF_SIZE];
int n = 0;
// 送信用
char file_name[64];
int file_size = -1;
char file_size_c[64];
char data[64];
// ソケット作成、入力はIP、ストリーム型、TCPを指定
int socketd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketd < 0)
{
handle_error("Fail to create a socket.\n");
}
// サーバのアドレス等を初期化
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(serv_ip);
serv_addr.sin_port = htons(serv_port);
// サーバに接続
n = connect(socketd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (n < 0)
{
handle_error("Fail to connect to the server.\n");
}
// サーバとの通信
while (1)
{
while (1)
{
// ユーザからのファイル名入力を待機
printf("サーバに送信するファイル名: ");
scanf("%s", file_name);
// ファイルの存在判定
if (access(file_name, F_OK) != -1)
{
printf("%s is found\n", file_name);
break;
}
else
{
printf("%s is not found\n", file_name);
}
}
// ファイルサイズを取得
file_size = get_file_size(file_name);
// ファイルサイズを文字列型に変換
snprintf(file_size_c, 64, "%d", file_size);
gettimeofday(&start_time, NULL);
/*--- ファイル名を送信 ---*/
n = write(socketd, file_name, sizeof(file_name));
if (n < 0)
{
handle_error("Fail to write a message.\n");
}
// サーバからACKを受信
n = read(socketd, buff, sizeof(buff));
if (n < 0)
{
handle_error("Fail to read a message.\n");
}
if (strcmp(buff, "ACK") == 0)
{
printf("ACKを受信(ファイル名受信)\n");
}
/*--- ファイルサイズを送信 ---*/
n = write(socketd, file_size_c, sizeof(file_size_c));
if (n < 0)
{
handle_error("Fail to write a message.\n");
}
// サーバからACKを受信
n = read(socketd, buff, sizeof(buff));
if (n < 0)
{
handle_error("Fail to read a message.\n");
}
if (strcmp(buff, "ACK") == 0)
{
printf("ACKを受信(ファイルサイズ受信)\n");
}
/*--- ファイルデータを送信(64バイトずつ) ---*/
// ファイル1(コピー元)を読み込みモードで開く。
int fd_in = open(file_name, O_RDONLY);
if (fd_in < 0)
{
handle_error("Fail to open a file.");
}
// 64バイトずつ送信
do
{
// 引数:1)ファイル記述子、2)読み込んだバイトを格納する変数、3)読み込むバイト数
// 戻り値は、実際に読み込んだバイト数。エラーの場合は-1が返される。
n = read(fd_in, data, sizeof(data));
if (n < 0)
{
handle_error("Fail to read bytes from the input file.\n");
}
// 書き出し
// 引数:1)ファイル記述子、2)書き出すバイトが格納された変数、3)書き込むバイト数
// 戻り値は、実際に読み込んだバイト数。エラーの場合は-1が返される。
n = write(socketd, data, n);
if (n < 0)
{
handle_error("Fail to read bytes from the input file.\n");
}
// コピー元ファイルを全て読みこめば、nの値が0となる。nが1以上でなければ、ループを抜ける。
}
while (n > 0);
// ファイルを閉じる。
close(fd_in);
// サーバからACKを受信
n = read(socketd, buff, sizeof(buff));
if (n < 0)
{
handle_error("Fail to read a message from socket.\n");
}
if (strcmp(buff, "ACK") == 0)
{
printf("ACKを受信(ファイル受信完了)\n");
}
gettimeofday(&end_time, NULL);
// RTTを計算
double diff_sec = end_time.tv_sec - start_time.tv_sec;
double diff_usec = end_time.tv_usec - start_time.tv_usec;
double diff_time = diff_sec + diff_usec * 0.001 * 0.001;
printf("RTT = %f [s]\n", diff_time);
// 終了コマンドが入力されたらプログラム終了
printf("qが入力されたら終了し、それ以外なら続行: ");
scanf("%s", buff);
n = write(socketd, buff, sizeof(buff));
if (n < 0)
{
handle_error("Fail to write a message.\n");
}
if (strcmp(buff, "q") == 0)
{
printf("終了します。\n");
break;
}
putchar('\n');
}
// ソケットを閉じる。
close(socketd);
}
/*
* 引数で受け取ったファイル名のファイルサイズを返す。
*/
int get_file_size(char *file_name)
{
int fd; // ファイル記述子(A file descriptor)
int file_size; // ファイルサイズ
// ファイルを開く。
fd = open(file_name, 0);
if (fd < 0) handle_error("Fail to open a file.");
// ポインタをファイルの最後に移動させる。lseek(.)は現在のポインタを返す。
// 従って、ファイルポインタをファイルの最後に移動させれば、ファイルのバイト数が分かる。
// 引数:ファイル記述子、オフセット、オフセットからのバイト数
// SEEK_ENDはファイルの最後を指す。
file_size = lseek(fd, 0, SEEK_END);
// ポインタをファイルの先頭に戻す。
lseek(fd, 0, SEEK_SET);
// ファイルを閉じる。
close(fd);
return file_size;
}