客户端
#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解码,然后再处理。