一,遇到問題
1.段溢出砂代?
根本原因:vector申請后沒有釋放蹋订,導致段溢出。
調試方法:通過gdb調試core文件找到原因刻伊。
解決方案:添加clear及swap函數(shù)來釋放內存露戒。
2.client沒有顯示出圖片?
根本原因:都沒有收到一張完整的圖片就開始imshow導致捶箱。
調試方法:添加imwrite把數(shù)據(jù)保存來看效果智什。
解決方法:添加waitkey延時
3.client通過imwrite只能保存幾張相對完好的圖片?imshow顯示為黑色
根本原因:imwrite的數(shù)據(jù)不完整丁屎。
調試方法:1. 通過添加握手來分別傳輸長度+jpg數(shù)據(jù)荠锭。
2. 通過打印log來看size的值是否和預期傳輸一致。
解決方法:client接收大數(shù)據(jù)時候晨川,需要while多次來接收证九,否則一個size的只總是小于預期接收,它只要收到數(shù)據(jù)共虑,則不會阻塞愧怜,代碼會繼續(xù)往下走。
二妈拌,直接學到的經(jīng)驗
- c++ vector的使用拥坛,申請控件,清空內存供炎,與char轉換渴逻。
- imwrite和imdecode等函數(shù)的應用。(jpg等壓縮參數(shù)值)
- send和revc函數(shù)的使用及返回值的作用音诫。
- socket通信的基本流程惨奕。
- socket大數(shù)據(jù)傳輸處理方式。socket的阻塞體驗竭钝。
- core的gdb調試方法梨撞。
- cmake添加g++編譯的方法。
- 各個c++函數(shù)對應的頭文件香罐。
- int轉字符串的方法卧波。
- stringstream的數(shù)據(jù)流使用。
11.通過編譯報錯來直接找到原因庇茫。
三港粱,直接了解的相關經(jīng)驗
- socket粘包處理方法。
- 顯示幀率與sleep時間的計算。
- jpg圖像的格式查坪。
四寸宏,客戶端和服務器交互說明
服務器向讀取攝像頭數(shù)據(jù)向客戶端先發(fā)長度,獲取客戶端ACK后再像客戶端發(fā)送壓縮為JPG的數(shù)據(jù)偿曙。
交互圖.png
五氮凝,linux 客戶端代碼
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include<vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <unistd.h>
#include <iostream>
using namespace std;
using namespace cv;
/* tansfer int to string */
string int2string(int value)
{
stringstream ss;
ss<<value;
return ss.str();
}
int main(int argc, char** argv)
{
int sockfd, n;
char recvline[4096], sendline[4096];
struct sockaddr_in servaddr;
#if 0
if( argc != 2){
printf("usage: ./client <ipaddress>\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<char> 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.capacity()<<endl;
vector<char>(vec).swap(vec);
//cout << "vector capacity afterswap:"<<vec.capacity()<<endl;
/* display the jpg in windows */
namedWindow("pic",WINDOW_AUTOSIZE);
if(!img_decode.empty()){
imshow("pic",img_decode);
}
/* reflash display window in every 33ms */
cvWaitKey(33);
/* save to file -- this function is optional */
j++;
filename = "pic"+int2string(j)+".jpg";
imwrite(filename,img_decode);
/* send ack signal cok to tell that I'm ready to handler next frame */
char cok[ 1 ]={0x55};
send(sockfd, cok, 1, 0);
}
}
六,服務器代碼
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
/* tansfer int to string */
string int2string(int value)
{
stringstream ss;
ss<<value;
return ss.str();
}
int main(int argc, char** argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
int sendbytes;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
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_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8080);
int opt = 1;
/* set port reuse */
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const void *)&opt,sizeof(opt)))
{
perror("setsockopt");
return -1;
}
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
if( listen(listenfd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
/* ---main task process--- */
Mat frame;
VideoCapture cap;
vector<unsigned char> 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;i<datalen;i++)
{
msgImage[i]=inImage[i];
}
/* get lenght response ack from client */
recv(connfd,cokstart,1,0);
if(cokstart[0] == 0x33)
{
vector<char>vec;
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<datalen;i++)
{
vec.push_back(msgImage[i]);
}
/* decode JPG data */
img_decode =imdecode(vec,CV_LOAD_IMAGE_COLOR);
j++;
/* display JPG data */
imshow("serpic",img_decode);
/* save JPG data to files */
filename="sevpic"+int2string(j)+".jpg";
imwrite(filename,img_decode);
/* send data to client */
sizejpg=send(connfd,msgImage,datalen,0);
printf("sizejpg:%x",sizejpg);
usleep(10000);
/* get response ack from client then can send the next frame*/
recv(connfd,cok,1,0);
}
}
}
/* if get key press than break display and stop the socket connection */
close(listenfd);
return 0;
}