TCP客户端发送图片,服务器端进行接收,接受后的图片显示不出来

TCP客户端发送图片,服务器端进行接受
运行结果及报错内容
客户端
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <thread>
#include <fstream>
#include <stdlib.h>
#include <fcntl.h>
#include "cs.h"

using namespace std;

#define PORT 8889
#define MSG_SIZE 4096
#define MAX_LINE 5
#define IP "127.0.0.1"



int client()
{
    char client_MSG[MSG_SIZE], server_MSG[MSG_SIZE];

    //初始化TCP结构体
    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_port = (PORT);
    serverAddr.sin_family = AF_INET;

    if (inet_pton(AF_INET, IP, (void *)&serverAddr.sin_addr) <= 0)
    {
        perror("client inet_pton err!");
        return -1;
    }

    //创建socket套接字
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        perror("server socket err!");
        return -1;
    }

    // connect连接
    if (connect(socket_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        perror("client connect err!");
        return -1;
    }

    cout << "Connect Success!." << endl;
    cin.ignore(1024, '\n'); // 去除上一个cin残留在缓冲区的\n

    // thread th;
    // th = thread(recv_server,socket_fd , client_MSG);

    //打开照片的文件描述符
    // char yuv_data[3110];
    FILE *fp = fopen("/home/hq/1.jpg", "r");
    // int fd1=open("/home/nvidia/1.jpg", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fp == NULL)
    {
        perror("fopen err!");
        return -1;
    }

    char buff[1024] = {0};
    char buf[1034] = {1, 2};

    //计算文件大小
    fseek(fp, 0L, SEEK_END);
    int file_len = ftell(fp);

    cout << "文件大小= " << file_len << endl;
    fseek(fp, 0L, SEEK_SET);

    while (1)
    {

        int len = fread(buff, 1, sizeof(buff), fp); // 1024

        if (0 == len)
        {
            cout << "read end...........\n";
            fseek(fp, 0, SEEK_SET);
            break;
        }

        buf[2] = len & 0xFF;
        buf[3] = (len >> 8) & 0xFF;
        buf[4] = (len >> 16) & 0xFF;
        buf[5] = (len >> 24) & 0xFF;

        //文件总大小
        buf[6] = file_len & 0xFF;
        buf[7] = (file_len >> 8) & 0xFF;
        buf[8] = (file_len >> 16) & 0xFF;
        buf[9] = (file_len >> 24) & 0xFF;

        cout << "文件大小= " << file_len << endl;

        // 1024
        memcpy(&buf[10], buff, len);

        cout << "len=" << len << endl;

        sleep(0.5);
        if (len > 0)
        {
            if (send(socket_fd, buf, len + 10, 0) < 0)
            {
                perror("client send err!");
            }
        }
        else
        continue;

#if 0
        memset(client_MSG, 0, sizeof(client_MSG));
        memset(server_MSG, 0, sizeof(server_MSG));

        
        cin.getline(client_MSG, sizeof(client_MSG)); // 不用cin,因为不能含空格

        if (strncmp(client_MSG, "quit", 4) == 0)
        {
            break;
        }

        //向服务器端发消息
        if (send(socket_fd, client_MSG, strlen(client_MSG), 0) < 0)
        {
            perror("client send err!");
            return -1;
        }

        cout << "send msg to <" << serverAddr.sin_addr.s_addr << ">--> " << client_MSG << endl;

        // 接收服务器的消息
        int s_len=recv(socket_fd,server_MSG,sizeof(server_MSG),0);
        if(s_len <=0 )
        {
            perror("client recv err!");
            return -1;
        }

        server_MSG[s_len]='\0';

        cout<<"recv msg form <"<<serverAddr.sin_addr.s_addr<<">--> "<<server_MSG<<endl;
#endif
    }
    fclose(fp);
}


```c++
服务器端
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <thread>
#include <stdlib.h>
#include <fcntl.h>
#include "cs.h"

using namespace std;

#define PORT 8889
#define MSG_SIZE 4096
#define MAX_LINE 5

int server()
{
    char client_MSG[MSG_SIZE], server_MSG[MSG_SIZE];

    //初始化TCP结构体
    struct sockaddr_in serverAddr;
    serverAddr.sin_port = (PORT);
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //创建socket套接字
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        perror("server socket err!");
        return -1;
    }

    // bind绑定套接字
    if (bind(socket_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        perror("server bind err!");
        return -1;
    }

    // listen被动监听
    if (listen(socket_fd, MAX_LINE) < 0)
    {
        perror("server listen err!");
        return -1;
    }

    cout << "Listening........\n";
    int client_fd;

    FILE *fp = fopen("/home/hq/8.jpg", "w");
    if (fp == NULL)
    {
        perror("fopen err!");
        return -1;
    }

    static int num = 0;

    while (1)
    {
        memset(client_MSG, 0, sizeof(client_MSG));
        memset(server_MSG, 0, sizeof(server_MSG));

        struct sockaddr_in clientAddr;
        socklen_t lens = sizeof(clientAddr);

        //返回用于通信的文件描述符
        client_fd = accept(socket_fd, (struct sockaddr *)&clientAddr, &lens);
        if (client_fd < 0)
        {
            perror("server accept err!");
            return -1;
        }

        cout << "server: connection from " << clientAddr.sin_addr.s_addr
             << ", port " << PORT
             << ", socket " << client_fd << endl;

        while (1)
        {

            char buf[2048] = {0};

            int rd = 0;
            

            int w_len = 0, file_len = 0,len=0;

            int i = 0;

            static int count = 0;

            while (1)
            {
                rd = recv(client_fd, &buf[i], sizeof(buf), 0);
                
                cout<<"recv = "<<rd<<endl;

                if (rd <= 0)
                {
                    cout << "RD<=0跳出" << endl;
                    break;
                }

                if (buf[i] == 1)
                {
                    ++i;
                    cout << "buf1==0x90-" << i << endl;
                }
                    

                if (buf[i] == 2)
                {
                    ++i;
                    cout << "buf1==0x81-" << i << endl;
                }

                len = (buf[i] | buf[i + 1] << 8 | buf[i + 2] << 16 | buf[i + 3] << 24);

                if (len > 0)
                {
                    
                    i += 4;
                    cout << "send的长度:" << len <<" "<<"i="<< i<<endl;
                }

                   file_len = (buf[i] | buf[i + 1] << 8 | buf[i + 2] << 16 | buf[i + 3] << 24);

                    i += 4;
                    cout << "file的长度:" << file_len <<" "<< "i="<< i<<endl;

                if (file_len < 0)
                {
                    cout << "file_len_获取失败\n";
                    // return -1;
                }
                
                  cout<<"進入寫入------------\n";
                  w_len = fwrite(&buf[i], 1, len, fp);
                  memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len])));
                  i=0;

                num = w_len + num;

                if (num >= file_len)
                {
                    if (num == file_len)
                    {
                        cout << "文件大小已经读取完成\n";
                        fseek(fp, 0, SEEK_SET);
                        count++;
                        num = 0;
                        return -1;
                    }
                }
                
                if(i==(sizeof(buf)))
                {
                    cout<<"buf==2048"<<endl;
                    // i=0;
                    break;
                }

            }

            //关闭通信套接字
            close(client_fd);

            cout << "当前客户端已结束通信,是否继续等待其他客户端?(1 - 是, 0 - 否)" << endl;
            bool isContinue = false;
            cin >> isContinue;
            if (!isContinue)
            {
                break;
            }
        }
    }
    fclose(fp);
    close(socket_fd);
    return 0;
}


``` 服务器端收2048个,报头含有标志和数据长度,图片传输过去服务器写入数据不对,提醒段错误

309行的 memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len]))); 是干什么的,把自身缓冲区后面的数据拷贝到自己缓冲区,有什么意义?

想要测出原因就要利用好调试工具:可以在百度里搜索“tcp串口调试助手”
1.判断你写的客户端(命名为C)是否存在问题,“tcp串口调试助手”建立一个tcp服务器(命名为S), C发送消息到S,如果S收到C发送的消息则说明服务器存在问题。
2.同理1判断服务器是否存在问题
3.判断出主要问题后就是问题的细化处理了

先发现了,如下几个可能得错误
第1 楼上提也提到的那句 memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len])));
这句先不管你是啥意思, 取长度的时候(sizeof(buf)-strlen(&buf[i+len])
注意是否超过buf和 buf从i+len开始的位置剩余的空间 如果超过越界肯定是段错误了
第2 tcp是流式的数据,rd = recv(client_fd, &buf[i], sizeof(buf), 0);
这句读到了数据rd个数据,你只判断了有数据,可能只收到比如3个字节的数据,
这样下面那些len都会可能错掉,超过2048,并且里面判断1和2那个头就算不对,程序还是往下走了
那么w_len = fwrite(&buf[i], 1, len, fp); 在写入的len的时候,可能会越界了。
一般是这样来读数据 先读长度len那几个字节,然后根据len在读取相应的长度数据。
按照目前的写法不是一个稳定的程序
第3 目前看可能段错误的是下面2个位置,加点调试看看len啥的变化情况
w_len = fwrite(&buf[i], 1, len, fp);
memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len])));

想要测出原因就要利用好调试工具:可以在百度里搜索“tcp串口调试助手”
1.判断你写的客户端(命名为C)是否存在问题,“tcp串口调试助手”建立一个tcp服务器(命名为S), C发送消息到S,如果S收到C发送的消息则说明服务器存在问题。
2.同理1判断服务器是否存在问题
3.判断出主要问题后就是问题的细化处理了
先发现了,如下几个可能得错误
第1 楼上提也提到的那句 memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len])));
这句先不管你是啥意思, 取长度的时候(sizeof(buf)-strlen(&buf[i+len])
注意是否超过buf和 buf从i+len开始的位置剩余的空间 如果超过越界肯定是段错误了
第2 tcp是流式的数据,rd = recv(client_fd, &buf[i], sizeof(buf), 0);
这句读到了数据rd个数据,你只判断了有数据,可能只收到比如3个字节的数据,
这样下面那些len都会可能错掉,超过2048,并且里面判断1和2那个头就算不对,程序还是往下走了
那么w_len = fwrite(&buf[i], 1, len, fp); 在写入的len的时候,可能会越界了。
一般是这样来读数据 先读长度len那几个字节,然后根据len在读取相应的长度数据。
按照目前的写法不是一个稳定的程序
第3 目前看可能段错误的是下面2个位置,加点调试看看len啥的变化情况
w_len = fwrite(&buf[i], 1, len, fp);
memcpy(buf,&buf[i+len],(sizeof(buf)-strlen(&buf[i+len])));

我初步看了一下楼主的代码,虽然没有细看每一行代码,但是首先发现基本原理的错误问题,客户端打开文件方式就错误了,应该使用二进制方式打开,比如open(file, "rb") 这样才能进行可靠的读取数据,服务端需要进行wb进行写入,这样服务端基本就可以查看图片的。然后逻辑传输没问题的话,那么肯定就没有任何问题的。

注意是否超过buf和 buf从i+len开始的位置剩余的空间 如果超过越界肯定是段错误了

首先,TCP发送和接收图片,不能这么直接收发二进制数据。你找个二进制查看文件,打开图片文件看下,一般中间数据有0的,碰到这种你发送和接收,怎么处理呢?
解决办法,发送端对图片二进制数据先base64编码,再发送;接收端收到数据后,base64解码,然后再处理。