Client 树莓派 4B 2G 运行 debian 11 x64 Server Macbook macOS 两者采用有线连接至同一台交换机中
在传输文件时有时成功,有时失败。失败时在终端打印乱码,但对于同一文件打印出来的乱码相同,个人猜测是编码问题,但是 debian 和 macOS 用的应该都是 UTF-8 ?而且传字符串没有问题
下面给出 Server 端和 Client 端的代码
//Server 接收端
struct PacketHeader {
int size; // 大小:字节
PacketHeader() {
size = 0;
}
};
void *receiveMsg(void *sock) {
// system("pwd");
char buffer[1024];
int *socket = (int *) sock;
while (1) {
usleep(500);
int nRecv = recv(*socket, buffer, 1024, 0);
if (nRecv <= 0) {
continue;
} else if (nRecv == sizeof(PacketHeader)) {
PacketHeader ph;
memcpy(&ph, buffer, nRecv);
cout << "大小:" << ph.size << "Bytes" << endl;
string filename = ("../Received/" + getCurrentTime() + ".jpg");
FILE *fp = fopen(filename.c_str(), "wb");
if (fp == NULL) {
cout << "file not found" << endl;
}
cout << "开始接收图片" << endl;
nRecv = 0;
while (nRecv < ph.size) {
usleep(500);
memset(buffer, 0, sizeof(buffer));
int byteCount = recv(*socket, buffer, 1024, 0);
if (byteCount <= 0) {
continue;
}
fwrite(buffer, 1, byteCount, fp);
nRecv += byteCount;
cout << "已接收 " << nRecv << " Bytes" << endl;
}
cout << "共接收 " << nRecv << " Bytes" << endl;
fclose(fp);
} else {
buffer[nRecv] = '\0';
cout << buffer << endl;
}
}
# Client 发送端
struct PacketHeader
{
int size; // 大小:字节
PacketHeader()
{
size = 0;
}
};
void *sendMsg(void *socket)
{
int sock = *((int *)socket);
while (1)
{
char msg[4096];
string filename;
cin >> filename;
FILE *fp = fopen(("../image/" + filename).c_str(), "rb");
if (fp == NULL)
{
cout << "file not found" << endl;
continue;
}
int sz = FileSize(("../image/" + filename).c_str());
cout << "文件打开成功,大小:" << sz << " Bytes" << endl;
PacketHeader ph;
ph.size = sz;
send(sock, (const char *)&ph, sizeof(ph), 0);
cout << "已发送头部信息" << endl;
int nSend = 0;
char buffer[1024];
while(nSend < sz)
{
int nBytes = fread(buffer, sizeof(char), sizeof(buffer), fp);
if (nBytes <= 0)
break;
send(sock, buffer, nBytes, 0);
cout << "已发送 " << nBytes << " Bytes" << endl;
nSend += nBytes;
}
cout<<"总计发送 "<<nSend<<" Bytes"<<endl;
fclose(fp);
cout << "successfully send " + filename << endl;
}
}
1
Kinnice 2022-02-20 22:07:00 +08:00 via Android 1
可能是发送太快,接受太慢,设置 sleep 试试,让它慢慢发
|
2
flynaj 2022-02-20 22:14:00 +08:00 via Android 1
其它协议正常不,samba ,FTP ,HTTP 这类
|
3
wevsty 2022-02-20 22:14:51 +08:00 1
nRecv == sizeof(PacketHeader)
这里并不能保证第一次接收正好收到一个 sizeof(PacketHeader)的大小。 虽然你先发送一个 sizeof(PacketHeader)大小的数据在发送其他的数据,但是接收端收到的时候很可能接收到更多的数据。 |
4
ysc3839 2022-02-20 22:34:06 +08:00 1
@wevsty TCP 发送的是流数据,多次调用 send 都是看作一整条流发出去的。接收端应该循环接收直到收到的数据长度大于等于 PacketHeader 的长度后再处理。另外 send 和 recv 的长度可能比缓冲区长度短的,也需要处理,建议调 API 时看文档怎么写的,不要想当然。
|
5
llr8031 OP @Kinnice 感谢回复,这边尝试了取消 recv 的 sleep ,在 send 部分增加了 usleep(1000),错误的概率比之前低了些,大概收发 5 次左右会出现一次乱码,一定程度上有效,谢谢
|
7
llr8031 OP @wevsty 感谢回复,嗯…我是看到 TCP 的粘包问题,网上的解决方案就是在发送前先发一个带有文件大小的包,参考的代码是 https://blog.csdn.net/zhoujielunzhimi/article/details/8190601 ,作者似乎没有遇到这个问题…不过作者测试的是 40B 的小文件,我测试的是 200KB 左右的大文件,一次 buffer 肯定装不下,所以猜测大概是这里的问题
|
9
inframe 2022-02-20 23:29:34 +08:00 1
懒惰一点,服务端监听的时候套一层 tls ,让 ssl 协议帮你处理 tcp 包问题,顺便安全问题也解决了;
|
10
koloonps 2022-02-20 23:42:55 +08:00 1
没有看到标识位,没有看到长度位,没有看到检验位...............................
|
13
documentzhangx66 2022-02-21 00:09:17 +08:00 1
1.初学别发文件,也别发字符串,而是发一个长度为 16 或 32 的 byte array ,方便你调试、对比与检查。
2.发送前,把要发送的内容,全部先装入一个完整的 byte array 里。 3.发送端,一个一个字节地发送。接收端,一个一个字节地接受。使用调试模式,单步运行,收到一个字节,就对比一下。 这样子,问题在哪,你就能自己找出来了。 数组发送没问题后,再来说说文件。 接收端,别单方面进行接受,而是,需要发送的文件,在接收端,也存一份。然后还是一个一个字节地收发,接收端,收到一个字节,就拿去和文件对比。当接收到不一样的字节时,那个代码位置,下个断点,进行调试,看看发生了什么问题。 上面的事情都解决后,恢复成正常 buffer 收发。你甚至可以用超大 buffer 来提高性能。 |
14
llr8031 OP @documentzhangx66 感谢指点,我结合书本试试看,喟叹 V 站颇有知乎遗风= v =
|
15
koloonps 2022-02-21 00:54:12 +08:00
你可以直接发送一个 byte[]用\n 作为结束符号
|
17
julyclyde 2022-02-22 12:52:59 +08:00
其实发送的时候可以随便 send 吧
接收的时候才存在收不奇的问题,需要预先知道长度才能知道是否需要继续收 |