通过套接字发送图像并将其保存在服务器上

时间:2016-11-17 16:35:44

标签: c# c sockets fwrite

我目前在项目中面临一些问题,我希望您能够识别我的问题,因为我自己无法看到它。

我试图将图片从C#客户端(Windows)发送到我在Linux系统上运行的C服务器。我通过TCP Socket传输图像二进制数据并且工作得很好,问题是当我用fwrite在linux系统上写入接收到的缓冲区时,似乎存在一些信息。缓冲区,不会写入或写入文件损坏的值。

E.g。我试图在这里发送这张照片:

enter image description here

我上了那台服务器:

enter image description here

客户:

    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);

    ...

如果我收到图像并将其直接发送回客户端,然后客户端将接收到的缓冲区写入文件,一切正常,已发送的文件与收到的文件之间没有区别。因此,我非常确定传输是按预期工作的。

如果您还需要更多信息,请与我们联系!

1 个答案:

答案 0 :(得分:1)

fopen创建缓冲的 I / O流。但是你不是要刷新缓冲区并关闭文件。切断错误检查,你正在做:

f = fopen(filename, "wb");
fwrite(buffer, sizeof (buffer[0]), image_size, f);

你应该在最后加上这些:

fflush(f);
fclose(f);

fclose实际上会为您冲洗,但最好单独进行冲洗,以便您可以在关闭之前检查错误。

这里发生的事情(有点过分简化)是:

  1. fopen在磁盘上创建文件(使用open(2) [或creat(2)]系统调用)并分配内部缓冲区
  2. fwrite重复填充内部缓冲区。每次缓冲区填充到某个边界(由BUFSIZ确定 - 请参阅setbuf(3)手册页),fwrite将其刷新到磁盘(即它进行write(2)系统调用)
  3. 但是,当你完成后,文件的结尾仍然位于内部缓冲区中 - 因为图书馆无法知道你已经完成了对文件的写入而你没有#39;碰巧在BUFSIZ边界上。 fflushfclose将告诉库清除最后一个部分缓冲区,将其写入磁盘。然后使用fclose底层OS文件描述符将被关闭(您应该始终无论如何,或者你的服务器将有&#34;文件描述符泄漏&#34;)。