一,遇到问题
1.段溢出?
根本原因:vector申请后没有释放,导致段溢出。
调试方法:通过gdb调试core文件找到原因。
解决方案:添加clear及swap函数来释放内存。
2.client没有显示出图片?
根本原因:都没有收到一张完整的图片就开始imshow导致。
调试方法:添加imwrite把数据保存来看效果。
解决方法:添加waitkey延时
3.client通过imwrite只能保存几张相对完好的图片?imshow显示为黑色
根本原因:imwrite的数据不完整。
调试方法:1. 通过添加握手来分别传输长度+jpg数据。
2. 通过打印log来看size的值是否和预期传输一致。
解决方法:client接收大数据时候,需要while多次来接收,否则一个size的只总是小于预期接收,它只要收到数据,则不会阻塞,代码会继续往下走。
二,直接学到的经验
- c++ vector的使用,申请控件,清空内存,与char转换。
- imwrite和imdecode等函数的应用。(jpg等压缩参数值)
- send和revc函数的使用及返回值的作用。
- socket通信的基本流程。
- socket大数据传输处理方式。socket的阻塞体验。
- core的gdb调试方法。
- cmake添加g++编译的方法。
- 各个c++函数对应的头文件。
- int转字符串的方法。
- stringstream的数据流使用。
11.通过编译报错来直接找到原因。
三,直接了解的相关经验
- socket粘包处理方法。
- 显示帧率与sleep时间的计算。
- jpg图像的格式。
四,客户端和服务器交互说明
服务器向读取摄像头数据向客户端先发长度,获取客户端ACK后再像客户端发送压缩为JPG的数据。
五,linux 客户端代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
/* tansfer int to string */
string int2string(int value)
{
stringstream ss;
ss<\n");
exit(0);
}
#endif
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8080);
if( inet_pton(AF_INET, "192.168.7.4", &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n",argv[1]);
exit(0);
}
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
#define BUF_SIZE 65535
char buffer[ BUF_SIZE ];
vector vec;
Mat img_decode;
string filename="";
int size = 0;
int mylen = 0;
int j= 0;
char cokstart[ 1 ]={0x33};
memset( buffer, 0, 4 );
while(1)
{
size = recv(sockfd,buffer,4,0);
mylen = ((buffer[2]<<8)&(0xFF00))|((buffer[3])&(0xFF));
if (mylen>0){
/*received length then send ack signal cokstart.*/
send(sockfd, cokstart, 1, 0);
}
/* receive one frame of jpg data */
while(mylen)
{
size=recv(sockfd,buffer,mylen,0);
//printf("size is %d\n",size);
//printf("mylen is %x\n",mylen);
/* put char values to vector */
for(int i = 0 ; i < mylen ; i ++)
{
vec.push_back(buffer[i]);
}
mylen = mylen-size;
}
/* decode jpg data */
img_decode = imdecode(vec, CV_LOAD_IMAGE_COLOR);
/* release vector then ready to receive next frame */
vec.clear();
//cout << "vector capacity:"<(vec).swap(vec);
//cout << "vector capacity afterswap:"<
六,服务器代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
/* tansfer int to string */
string int2string(int value)
{
stringstream ss;
ss< inImage;
/* open camera */
cap.open(0);
if (!cap.isOpened())
{
cerr << "ERROR! Unable to open camera\n";
return -1;
}
printf("open camera success\n");
printf("======waiting for client's apple request======\n");
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
exit(0);
}
char cok[1]={0x55};
char cokstart[1]={0};
char j=0;
int sizelen=0;
int sizejpg=0;
for (;;)
{
/* read one frame */
cap.read(frame);
/* check if we succeeded */
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
/* stop display after get key press */
if(waitKey(5)>=0)
break;
/* get trigger from client's command */
if (cok[0]==0x55){
cok[0]=0;
//printf("read one frame!\n");
/* encode frame to JPG data */
imencode(".jpg",frame,inImage);
/* get length of jpg */
int datalen=inImage.size();
/* prepare char to save jpg data */
unsigned char *msgImage=new unsigned char[datalen];
unsigned char msgLen[4];
msgLen[0]=datalen >> 24;
msgLen[1]=datalen >> 16;
msgLen[2]=datalen >> 8;
msgLen[3]=datalen;
//printf("datalen=%x\n",datalen);
/* send lenght to client first */
sizelen=send(connfd,msgLen,4,0);
//printf("sizelen:%x",sizejpg);
/* put vector data to char */
for(int i=0;ivec;
Mat img_decode;
string filename="";
/* decode than save display to save to file. This is optional function */
cokstart[0]=0x0;
/* put data to vector */
for(int i=0;i