cpp
clnt_sd=accept(serv_sd, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
read(clnt_sd, file_name, BUF_SIZE);
fp=fopen(file_name, "rb"); //尝试打开客户端请求的文件
if(fp!=NULL) //如果文件存在,则传送给客户端
{
while(1)
{
read_cnt=fread((void*)buf, 1, BUF_SIZE, fp);
if(read_cnt<BUF_SIZE)
{
write(clnt_sd, buf, read_cnt);
break;
}
write(clnt_sd, buf, BUF_SIZE);
}
}
在C++中,`fread`是一个函数,用于从文件中读取数据。它的原型如下:
cpp
size_t fread(void* ptr, size_t size, size_t count, FILE* stream);
其中,`ptr`是一个指向存储读取数据的内存块的指针;`size`是每个数据块的字节数;`count`是要读取的数据块数;`stream`是一个指向要读取的文件的指针。
`fread`函数将从文件中读取`count`个数据块,每个数据块的大小为`size`字节,然后将这些数据存储到`ptr`指向的内存块中。函数返回实际读取的数据块数,如果读取失败或到达文件末尾,返回的值可能小于`count`。
以下是一个使用`fread`函数读取二进制文件的示例:
cpp
#include <iostream>
#include <cstdio>
int main() {
FILE* fp = std::fopen("data.bin", "rb");
if (fp == nullptr) {
std::perror("Failed to open file");
return 1;
}
int buffer[4];
std::size_t count = std::fread(buffer, sizeof(int), 4, fp);
if (count != 4) {
std::perror("Failed to read file");
return 1;
}
for (int i = 0; i < 4; ++i) {
std::cout << buffer[i] << " ";
}
std::fclose(fp);
return 0;
}
在上面的示例中,我们打开了一个名为"data.bin"的二进制文件,并使用`fread`函数读取了其中的4个整数。`fread`函数将这些整数存储到`buffer`数组中,然后我们将这些整数输出到控制台。需要注意的是,我们使用了"rb"作为打开文件的方式,以确保文件以二进制方式打开。
上述代码的含义是:
-
`clnt_sd=accept(serv_sd, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);`:通过服务器套接字`serv_sd`接受客户端的连接请求,并创建一个新的套接字`clnt_sd`来与客户端进行通信。这个函数用于服务器端接受客户端的连接请求。
-
`read(clnt_sd, file_name, BUF_SIZE);`:从已连接的套接字`clnt_sd`中读取客户端发送的文件名,并将其存储到`file_name`变量中。
-
`fp=fopen(file_name, "rb");`:尝试以只读二进制方式打开客户端请求的文件。如果文件存在,则返回一个指向该文件的文件指针`fp`。
-
`if(fp!=NULL)`:如果文件指针`fp`不为空,即文件存在,则执行下面的代码块。
-
`while(1)`:无限循环,用于从文件中读取数据并发送给客户端。
-
`read_cnt=fread((void*)buf, 1, BUF_SIZE, fp);`:从文件中读取最多`BUF_SIZE`字节的数据,并将其存储到缓冲区`buf`中。`fread`函数返回实际读取的字节数。
-
`if(read_cnt<BUF_SIZE)`:如果实际读取的字节数小于`BUF_SIZE`,说明已经读取到了文件末尾。
-
`write(clnt_sd, buf, read_cnt);`:将从文件中读取的数据通过已连接的套接字`clnt_sd`发送给客户端。
-
`break;`:跳出循环,结束文件传输。
-
`write(clnt_sd, buf, BUF_SIZE);`:将从文件中读取的数据块`buf`通过已连接的套接字`clnt_sd`发送给客户端。
综合起来,这段代码的作用是服务器端接受客户端连接请求,读取客户端发送的文件名,并尝试打开该文件。如果文件存在,则从文件中读取数据并通过已连接的套接字发送给客户端。这段代码适用于服务器端响应客户端下载文件的请求。
在服务器向客户端发送文件数据时,可能存在以下两种情况:
-
文件大小正好是`BUF_SIZE`的整数倍:此时每次从文件中读取`BUF_SIZE`字节的数据块,并使用`write(clnt_sd, buf, BUF_SIZE)`将数据块发送给客户端。
-
文件大小不是`BUF_SIZE`的整数倍:此时最后一次从文件中读取的数据块大小可能小于`BUF_SIZE`,因此需要使用`write(clnt_sd, buf, read_cnt)`将实际读取的数据块发送给客户端。
因此,在`while`循环中需要使用两次`write`函数,分别处理上述两种情况。第一次使用`write(clnt_sd, buf, BUF_SIZE)`发送完整的数据块,第二次使用`write(clnt_sd, buf, read_cnt)`发送最后一次读取的不完整的数据块。这样可以确保将整个文件的数据都发送给客户端。