用阻塞socket传输文件recv速度太慢

kmij261 2016-10-20 09:28:13
服务器和客户端都在局域网下,都用的阻塞模式,测试文件为100k大小的图片。
服务器发送一帧只需要40ms,但是客户端接收一帧需要480ms左右(只是recv过程),感觉不应该这么慢...请问怎么把速度提上去?还有就是接收完一帧,用opencv自带的imread读取图像时发现是空的...

#include"stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include"iostream"
#include"opencv2/opencv.hpp"

using namespace cv;
using namespace std;
#define PORT 8000
#define SERVER_IP "192.168.1.107"
#define BUFFER_SIZE 4096
#define FILE_NAME_MAX_SIZE 512
#pragma comment(lib, "WS2_32")

double rate = 1.0;//视频帧率
Size videosize(640,480);

int64 startTime ;//开始运行程序时的时钟周期数
double duration;//运行到现在所用时间

const string &filename="objtr";//文件名
const string &ext = ".jpg";//文件后缀名
int recvFile(char file_name[FILE_NAME_MAX_SIZE], SOCKET clientSocket);
double timeCost(int64 beginTime);

int main()
{
int i=1;
//创建视频写入实例
VideoWriter writer("VideoTest.avi", CV_FOURCC('M', 'J', 'P', 'G'), rate,videosize);

stringstream ss;
char file_name[FILE_NAME_MAX_SIZE+1];
memset(file_name,0,FILE_NAME_MAX_SIZE+1);

// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 0);
if(WSAStartup(socketVersion, &wsaData) != 0)
{
printf("Init socket dll error!");
exit(1);
}

//创建socket
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == clientSocket)
{
printf("Create Socket Error!");
system("pause");
exit(1);
}
cout << "创建socket成功" <<endl;

//指定服务端的地址
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(PORT);

if (SOCKET_ERROR == connect(clientSocket, (LPSOCKADDR)&server_addr, sizeof(server_addr)))
{
printf("Can Not Connect To Server IP!\n");
system("pause");
exit(1);
}
cout << "连接服务器成功" <<endl;

while(1)
{
startTime = getTickCount();//读取系统周期数

ss << filename << i << ext ;
ss >> file_name;
int writen;//判断写入是否成功

writen = recvFile(file_name,clientSocket);//写入文件

if(!writen)
{
break;
}

cout << "文件 "<<file_name<< "接收成功" <<endl;

Mat frame = imread(file_name);
writer << frame;
imshow("display",frame);

send(clientSocket,"~", 1, 0);
ss.clear();
i++;
duration = timeCost(startTime);
cout<< "本次用时:" << duration << "s" <<endl<<endl;
}
closesocket(clientSocket);

//释放winsock库
WSACleanup();


return 0;
}

int recvFile(char file_name[FILE_NAME_MAX_SIZE+1], SOCKET clientSocket)
{
int recvLen=0;//收到的缓冲的长度
int recvedLen=0;//当前已经收到的长度
char* buffer;//文件缓冲
char recvBuffer[BUFFER_SIZE];//接收缓冲区
int retval;


buffer=new char[1024*150];
recvLen=recv(clientSocket,recvBuffer,BUFFER_SIZE,0);
if(recvBuffer[0]=='~')
{
printf("开始接收文件\n");
memset(recvBuffer,0,BUFFER_SIZE);
}
duration = timeCost(startTime);
while(true)
{
recvLen=recv(clientSocket,recvBuffer,BUFFER_SIZE,0);
if(!recvLen)
break;
else
{
memcpy(buffer+recvedLen,recvBuffer,recvLen);
recvedLen += recvLen;
}
}
printf("已经接收%i字节数据\n",recvedLen);
duration = timeCost(startTime)- duration;
cout<< "recv所用时间:" << duration << "s" <<endl;

cout << "开始写入" <<endl;
FILE *fp;
if((fp = fopen(file_name,"wb")) == NULL)
{

exit(1);
}

retval = fwrite(buffer, recvedLen, 1, fp);
printf("写入文件长度:%u\n",recvedLen);

fclose(fp);

return retval;
}

double timeCost(int64 beginTime)
{
double duration;
duration = (getTickCount()-beginTime)/getTickFrequency();

return duration ;
}

...全文
1362 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2016-10-26
  • 打赏
  • 举报
回复
任何收发两端速度不一致的通讯,都需要在它们之间使用一个足够大的FIFO缓冲区。 对任何FIFO缓冲区的使用,都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已满这两种情况下该如何做。
starytx 2016-10-26
  • 打赏
  • 举报
回复
看样子是你自己没有规划好发送接收规则(或者说收发协议),对你的数据进行包装,每块数据带上头信息,比如第几块数据,是否结束等标记,接收端对收到的数据块进行分析并合并到缓冲区
eastfriendwu 2016-10-26
  • 打赏
  • 举报
回复
如果服务器只是发送文件,没有其它交互,可以这样:每发送一个文件内容之前,先发送文件长度,然后文件内容。
客户端先接收,解析出长度,根据长度接收文件内容。不需要发送字符~#。
如果交互复杂,可以定义消息头,消息体等,像楼上那位说的。
kmij261 2016-10-25
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
不好意思赵老师我没太看懂,我这套程序是这样的: 服务器端 1.发送一个 '~' ,等待客户端确认; 2.客户端确认后发送文件,发送 '#' 表示文件结束,等待客户端回传一个 '~' ; 2.收到 '~' 符号后,继续下一次循环/color] [color=#FF0000]客户端 1.从服务器接收 '~' 2.收到符号后,开始接收文件,直到读到 '#' ,接收文件结束,保存文件 3.向服务器发送 '~',继续下一次循环 感觉是服务器转发送文件后,告诉客户端文件发送结束时,客户端把' #' 当做了文件末尾,然后卡在接收中无法退出了 ,请问怎么解决呢?
kmij261 2016-10-25
  • 打赏
  • 举报
回复
引用 6 楼 eastfriendwu 的回复:
[quote=引用 4 楼 kmij261 的回复:] [quote=引用 3 楼 zhao4zhong1 的回复:] 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
请问赵老师,为什么在88行 用imread读图片的时候,读出来的frame是空的,但是我用资源管理器打开的时候图片是存在的,而且是完好的呢?[/quote] 我不了解opencv, 但是网上很多人遇到你的问题。这是我随便搜的。 。。。。。。。 ,然后就是imread读文件问题,即使链接库版本正确(debug的库为xxxd.dll,release的库为xxx.dll),参数正确,在debug模式下也无法读文件,release模式下能读文件。找了很久,终于找到解决办法: 如果是debug版,将运行时库设置为:多线程调试(/ MTD) 如果是release版,将运行时库设置为:多线程(/ MT) 当然,如果觉得不好用,可以换一种方法,就是通过 IplImage*iplImg = cvLoadImage(filename.c_str(),1); Mat input_image(iplImg,true); 来获得你需要的矩阵,这样也很方便,不一定要在imread上面死抠,没什么意思! 。。。。。。。 http://blog.csdn.net/lh1162810317/article/details/23792247[/quote] 是我代码的问题,之前弄错了,非常感谢!
赵4老师 2016-10-23
  • 打赏
  • 举报
回复
提醒:OpenCV是开源的。
eastfriendwu 2016-10-22
  • 打赏
  • 举报
回复
引用 4 楼 kmij261 的回复:
[quote=引用 3 楼 zhao4zhong1 的回复:] 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
请问赵老师,为什么在88行 用imread读图片的时候,读出来的frame是空的,但是我用资源管理器打开的时候图片是存在的,而且是完好的呢?[/quote] 我不了解opencv, 但是网上很多人遇到你的问题。这是我随便搜的。 。。。。。。。 ,然后就是imread读文件问题,即使链接库版本正确(debug的库为xxxd.dll,release的库为xxx.dll),参数正确,在debug模式下也无法读文件,release模式下能读文件。找了很久,终于找到解决办法: 如果是debug版,将运行时库设置为:多线程调试(/ MTD) 如果是release版,将运行时库设置为:多线程(/ MT) 当然,如果觉得不好用,可以换一种方法,就是通过 IplImage*iplImg = cvLoadImage(filename.c_str(),1); Mat input_image(iplImg,true); 来获得你需要的矩阵,这样也很方便,不一定要在imread上面死抠,没什么意思! 。。。。。。。 http://blog.csdn.net/lh1162810317/article/details/23792247
kmij261 2016-10-22
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
请问赵老师,为什么在88行 用imread读图片的时候,读出来的frame是空的,但是我用资源管理器打开的时候图片是存在的,而且是完好的呢?
赵4老师 2016-10-22
  • 打赏
  • 举报
回复
乍看起来c++的cin、cout、ifstream、ofstream、istringstream、ostringstream在输入、输出上比c的scanf、printf、fscanf、fprintf、fread、fwrite、sscanf、sprintf简单,不用格式控制符! 但是不用格式控制符,输入输出恰好是你期望的格式的时候好说;等到输入输出不是你期望的格式的时候,你就会觉得还是用格式控制符更方便、更靠谱。 摒弃cin、cout、ifstream、ofstream、istringstream、ostringstream! 使用scanf、printf、fscanf、fprintf、fread、fwrite、sscanf、sprintf。
赵4老师 2016-10-21
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
kmij261 2016-10-20
  • 打赏
  • 举报
回复
引用 1 楼 eastfriendwu 的回复:
第一次recv时,不止接收到字符'~',应该还包括图片的内容,你把它给丢弃了,文件肯定被破坏了。
服务器发送时是先发一个'~',然后等待20ms,清空buffer再发送图片,保存的图片文件都是可以打开的完好图片。
eastfriendwu 2016-10-20
  • 打赏
  • 举报
回复
第一次recv时,不止接收到字符'~',应该还包括图片的内容,你把它给丢弃了,文件肯定被破坏了。

679

社区成员

发帖
与我相关
我的任务
社区描述
智能路由器通常具有独立的操作系统,包括OpenWRT、eCos、VxWorks等,可以由用户自行安装各种应用,实现网络和设备的智能化管理。
linuxpython 技术论坛(原bbs)
社区管理员
  • 智能路由器社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧