通过套接字发送图像并将其保存在服务器上
Sending image over socket and saving it on the server
我的项目目前遇到了一些问题,我希望你能找出我的问题,因为我自己无法看到它。
我正在尝试将图片从 C# 客户端 (Windows) 发送到我的 运行 在 linux 系统上的 C 服务器。我正在通过 TCP 套接字传输图像二进制数据并且工作正常,问题是当我使用 fwrite 在 linux 系统上写入接收到的缓冲区时,似乎有些信息存在于缓冲区,未写入文件或使用损坏的值写入文件。
例如我正在尝试将这张照片发送到这里:
我在服务器上得到的那个:
客户:
public static void sendPicture(Image image)
{
Byte[] imageBytes;
using (MemoryStream s = new MemoryStream())
{
image.Save(s, ImageFormat.Jpeg);
imageBytes = s.ToArray();
s.Close();
}
if (imageBytes.Length <= 5242880)
{
try
{
NetworkStream stream = client.GetStream();
File.WriteAllBytes("before.jpg", imageBytes);
//Send image Size
Byte[] imgSize = BitConverter.GetBytes((UInt32)imageBytes.Length);
stream.Write(imgSize, 0, imgSize.Length);
//Get answer from server if filesize is ok
Byte[] data = new Byte[1];
// recv only looks if we have a partial read,
// works like stream.Read(data, 0, data.Length)
Int32 count = recv(stream, data, data.Length);
if (count != 1 || data[0] != 0x4)
return;
stream.Write(imageBytes, 0, imageBytes.Length);
...
}
服务器:
...
// INFO_BUFFER_SIZE (1)
buffer = malloc(INFO_BUFFER_SIZE);
// does allow parital reads
if (read_from_client(connfd, buffer, INFO_BUFFER_SIZE) == NULL) {
error_out(buffer,
"Error during receiv of client data @ read_from_client");
close(connfd);
continue;
}
// reconstruct the image_size
uint32_t image_size =
buffer[3] << (0x8 * 3) | buffer[2] << (0x8 *2) | buffer[1] << 0x8 |
buffer[0];
fprintf(stderr, "img size: %u\n", image_size);
// Check if file size is ok
if (check_control(image_size, 1, response) > 0) {
inform_and_close(connfd, response);
continue;
}
// Inform that the size is ok and we're ready to receive the image now
(void) send(connfd, response, CONT_BUFFER_SIZE, 0);
free(buffer);
buffer = malloc(image_size);
if (read_from_client(connfd, buffer, image_size) == NULL) {
error_out(buffer,
"Error during receiv of client data @ read_from_client");
close(connfd);
continue;
}
FILE * f;
// Generate a GUID for the name
uuid_t guid;
uuid_generate_random(guid);
char filename[37];
uuid_unparse(guid, filename);
if ((f = fopen(filename, "wb")) == NULL) {
inform_and_close(connfd, 0x0);
error_out(buffer,
"Error while trying to open a file to save the data");
continue;
}
if (fwrite(buffer, sizeof(buffer[0]), image_size, f) != image_size) {
inform_and_close(connfd, 0x0);
error_out(buffer, "Error while writing to file");
continue;
}
char output[100];
(void) snprintf(output, sizeof(output), "mv %s uploads/%s.jpg",
filename, filename);
system(output);
free(buffer);
close(connfd);
...
如果我收到图片直接发回给客户端,然后客户端将接收到的缓冲区写入文件,一切正常,发送的文件和接收的文件没有区别.因此,我非常确定传输会按预期工作。
如果您还需要什么,请告诉我!
fopen
创建一个 缓冲 I/O 流。但是您没有刷新缓冲区并关闭文件。删除错误检查,你正在做:
f = fopen(filename, "wb");
fwrite(buffer, sizeof (buffer[0]), image_size, f);
你应该在最后添加这些:
fflush(f);
fclose(f);
fclose
实际上会为您冲洗,但最好单独进行冲洗,以便您可以在关闭前检查错误。
这里发生的事情(有点过于简单化)是:
fopen
在磁盘上创建文件(通过使用 open(2)
[或 creat(2)
] 系统调用)并分配一个内部缓冲区
fwrite
重复填充内部缓冲区。每次缓冲区填充到某个边界(由 BUFSIZ
确定——参见 setbuf(3)
手册页),fwrite
将其刷新到磁盘(即它执行 write(2)
系统调用) .
然而,当您完成后,文件末尾仍位于内部缓冲区中——因为库无法知道您已完成对文件的写入,而您恰好没有在 BUFSIZ
边界上。 fflush
或 fclose
将告诉库清除最后的部分缓冲区,将其写入磁盘。然后使用 fclose
将关闭底层 OS 文件描述符(无论如何你都应该这样做,否则你的服务器将有一个 "file descriptor leak").
我的项目目前遇到了一些问题,我希望你能找出我的问题,因为我自己无法看到它。
我正在尝试将图片从 C# 客户端 (Windows) 发送到我的 运行 在 linux 系统上的 C 服务器。我正在通过 TCP 套接字传输图像二进制数据并且工作正常,问题是当我使用 fwrite 在 linux 系统上写入接收到的缓冲区时,似乎有些信息存在于缓冲区,未写入文件或使用损坏的值写入文件。
例如我正在尝试将这张照片发送到这里:
我在服务器上得到的那个:
客户:
public static void sendPicture(Image image)
{
Byte[] imageBytes;
using (MemoryStream s = new MemoryStream())
{
image.Save(s, ImageFormat.Jpeg);
imageBytes = s.ToArray();
s.Close();
}
if (imageBytes.Length <= 5242880)
{
try
{
NetworkStream stream = client.GetStream();
File.WriteAllBytes("before.jpg", imageBytes);
//Send image Size
Byte[] imgSize = BitConverter.GetBytes((UInt32)imageBytes.Length);
stream.Write(imgSize, 0, imgSize.Length);
//Get answer from server if filesize is ok
Byte[] data = new Byte[1];
// recv only looks if we have a partial read,
// works like stream.Read(data, 0, data.Length)
Int32 count = recv(stream, data, data.Length);
if (count != 1 || data[0] != 0x4)
return;
stream.Write(imageBytes, 0, imageBytes.Length);
...
}
服务器:
...
// INFO_BUFFER_SIZE (1)
buffer = malloc(INFO_BUFFER_SIZE);
// does allow parital reads
if (read_from_client(connfd, buffer, INFO_BUFFER_SIZE) == NULL) {
error_out(buffer,
"Error during receiv of client data @ read_from_client");
close(connfd);
continue;
}
// reconstruct the image_size
uint32_t image_size =
buffer[3] << (0x8 * 3) | buffer[2] << (0x8 *2) | buffer[1] << 0x8 |
buffer[0];
fprintf(stderr, "img size: %u\n", image_size);
// Check if file size is ok
if (check_control(image_size, 1, response) > 0) {
inform_and_close(connfd, response);
continue;
}
// Inform that the size is ok and we're ready to receive the image now
(void) send(connfd, response, CONT_BUFFER_SIZE, 0);
free(buffer);
buffer = malloc(image_size);
if (read_from_client(connfd, buffer, image_size) == NULL) {
error_out(buffer,
"Error during receiv of client data @ read_from_client");
close(connfd);
continue;
}
FILE * f;
// Generate a GUID for the name
uuid_t guid;
uuid_generate_random(guid);
char filename[37];
uuid_unparse(guid, filename);
if ((f = fopen(filename, "wb")) == NULL) {
inform_and_close(connfd, 0x0);
error_out(buffer,
"Error while trying to open a file to save the data");
continue;
}
if (fwrite(buffer, sizeof(buffer[0]), image_size, f) != image_size) {
inform_and_close(connfd, 0x0);
error_out(buffer, "Error while writing to file");
continue;
}
char output[100];
(void) snprintf(output, sizeof(output), "mv %s uploads/%s.jpg",
filename, filename);
system(output);
free(buffer);
close(connfd);
...
如果我收到图片直接发回给客户端,然后客户端将接收到的缓冲区写入文件,一切正常,发送的文件和接收的文件没有区别.因此,我非常确定传输会按预期工作。
如果您还需要什么,请告诉我!
fopen
创建一个 缓冲 I/O 流。但是您没有刷新缓冲区并关闭文件。删除错误检查,你正在做:
f = fopen(filename, "wb");
fwrite(buffer, sizeof (buffer[0]), image_size, f);
你应该在最后添加这些:
fflush(f);
fclose(f);
fclose
实际上会为您冲洗,但最好单独进行冲洗,以便您可以在关闭前检查错误。
这里发生的事情(有点过于简单化)是:
fopen
在磁盘上创建文件(通过使用open(2)
[或creat(2)
] 系统调用)并分配一个内部缓冲区fwrite
重复填充内部缓冲区。每次缓冲区填充到某个边界(由BUFSIZ
确定——参见setbuf(3)
手册页),fwrite
将其刷新到磁盘(即它执行write(2)
系统调用) .
然而,当您完成后,文件末尾仍位于内部缓冲区中——因为库无法知道您已完成对文件的写入,而您恰好没有在 BUFSIZ
边界上。 fflush
或 fclose
将告诉库清除最后的部分缓冲区,将其写入磁盘。然后使用 fclose
将关闭底层 OS 文件描述符(无论如何你都应该这样做,否则你的服务器将有一个 "file descriptor leak").