本文使用OpenCV和socket传输图片,采用了固定图片大小的方式,且暂时不考虑手动分包的问题。
Server.cpp
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
const int PORT = 5678; //端口号
//const char *IP = "192.168.3.6"; //IP地址
struct sockaddr_in server_addr, client_addr; //定义服务端和客户端的地址结构体
const int Width = 640; //图片的宽
const int Heigth = 480; //图片的高
cv::Mat GetImage(int sockfd);
void InitAddr(int sokckfd);
int main(int argc, char **argv)
{
char client_IP[1024];
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //TCP传输
if (sockfd == -1)
{
perror("socket error");
exit(EXIT_FAILURE);
}
InitAddr(sockfd); //初始化地址,并将地址结构体绑定到套接字上
//阻塞等待客户端的连接请求
while (true)
{
bzero(&client_addr, sizeof(client_addr));
socklen_t client_len = sizeof(client_addr);
std::cout<<"wait"<<std::endl;
int connectfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
if (connectfd == -1)
{
perror("accept errno");
exit(1);
}
//打印客户端的IP地址和端口号
printf("client ip:%s port:%d\n",
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_IP, 1024),
ntohs(client_addr.sin_port));
//此时就可以读取connectfd中的数据
cv::Mat image = GetImage(connectfd);
//保存图片
cv::imwrite("../Get/image.jpg", image);
}
return 0;
}
void InitAddr(int sockfd)
{
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//设置端口复用
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret == -1)
{
perror("bind errno");
exit(1);
}
//std::cout<<"bind success"<<std::endl;
ret = listen(sockfd, 10);
if (ret == -1)
{
perror("listen errno");
exit(1);
}
//std::cout<<"listen success"<<std::endl;
}
cv::Mat GetImage(int connectfd)
{
cv::Mat mat = cv::Mat::zeros(Heigth, Width, CV_8UC1);
const int imgSize = mat.total() * mat.elemSize();
uchar bufferData[imgSize*2 ];
int bytes = 0;
int i = 0;
for (i = 0; i < imgSize; i += bytes)
{
bytes = recv(connectfd, bufferData + i, imgSize - i, 0);
if (bytes == -1)
{
std::cout << "status == -1 errno == " << errno << " in Socket::recv\n";
exit(EXIT_FAILURE);
}
}
// std::cout << "recv " << i << "bytes" << std::endl;
mat = cv::Mat(Heigth, Width, CV_8UC1, bufferData);
return mat;
}
Client.cpp
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
const int PORT = 5678; //端口号
const char *IP = "127.0.0.1"; //IP地址
struct sockaddr_in server_addr; //定义服务端的地址结构体
const int Width = 640; //图片的宽
const int Heigth = 480; //图片的高
void SendImage(const cv::Mat &mat, int sockfd);
void InitAddr();
int main(int argc, char **argv)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //TCP通信
if (sockfd == -1)
{
perror("socket errno");
exit(EXIT_FAILURE);
}
InitAddr();
//std::cout<<"socket success"<<std::endl;
int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
if(ret == -1)
{
perror("connect error");
exit(1);
}
std::cout<<"connect succedd"<<std::endl;
cv::Mat Srcimage = cv::imread("../Send/img1.jpg",0);
cv::Mat image;
cv::resize(Srcimage,image,cv::Size(Width,Heigth));
SendImage(image,sockfd);
close(sockfd);
return 0;
}
void InitAddr()
{
//std::cout<<"Initing"<<std::endl;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
//需要将服务器端的IP地址进行转换
int ret = inet_pton(AF_INET, IP, &server_addr.sin_addr.s_addr);
if (ret == -1)
{
perror("inet_pton error");
exit(EXIT_FAILURE);
}
}
void SendImage(const cv::Mat &mat, int sockfd)
{
int ret = send (sockfd, mat.data, mat.cols * mat.rows, MSG_NOSIGNAL );
if(ret == -1)
{
perror("send error");
exit(EXIT_FAILURE);
}
}