Hello, thank-you in advance for any help that may be provided here:
I am trying to send a Mat image from a server to a client over TCP-ip with winsock (between two different PC's). Like many others in these forums I am also new to socket programming. I have followed this very good thread "https://answers.opencv.org/question/197414/sendreceive-vector-mat-over-socket-cc/" which I have basically adopted for my own solution. Thank-you therefore to the contributors (pwk3, berak & opalmirror).
I have "successfully" been able to send a uchar vector, (converted from cv::Mat via imencode(..)) which appears to be exactly the same size when received on the client-side in comparison to the server-side prior to sending.
Unfortunately however when I try to decode it on the client side it results in an empty matrix. According to the docs: "If the buffer is too short or contains invalid data, the function returns an empty matrix ( Mat::data==NULL )."
Therefore I am assuming that although the exact number of bytes were sent... there is still some corruption somewhere.
If I decode the encoded buffer on the server side before transmission the original Mat is directly recoverable with the same code. Hence the issue has to occur in the transmission between PC's somehow.
I have attached code replicating the problem whereby the server sends one image and the receiver receives the full buffer but fails to decode:
If someone could please assist in perhaps explaining why I am able to decode on the server side without obtaining an empty Mat but not on the client that would be much appreciated. I feel the data must somehow be corrupted during transmission (even though it looks as though all data was received). Any tips would be much appreciated.
Thank-you in advance.
// ~~~~~~~~~~~~~~~~~~~~ Code Server: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include <ws2tcpip.h>
include <string>
include <vector>
include <opencv2 core="" core.hpp="">
include <opencv2 highgui="" highgui.hpp="">
include <opencv2 imgproc="" imgproc.hpp="">
include <opencv2 opencv.hpp="">
include <opencv2 core="" utils="" trace.hpp="">
using namespace cv;
int main(int argc, char* argv[])
{
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsInit = WSAStartup(ver, &data);
// 2. Create listening socket
SOCKET listener = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in hints;
hints.sin_family = AF_INET;
hints.sin_port = htons(54000);
WSADATA wsa_Data;
int wsa_ReturnCode = WSAStartup(0x101, &wsa_Data);
// 3. Get the local ipAddress
char szHostName[255];
gethostname(szHostName, 255);
struct hostent* host_entry;
host_entry = gethostbyname(szHostName);
char* ipAddress;
ipAddress = inet_ntoa(*(struct in_addr*)*host_entry->h_addr_list);
inet_pton(AF_INET, std::string(ipAddress).c_str(), &hints.sin_addr);
// 4. Bind socket
int bind_ok = bind(listener, (sockaddr*)&hints, sizeof(hints));
if (bind_ok != SOCKET_ERROR) {
if (listen(listener, SOMAXCONN) == SOCKET_ERROR)
return 0;
}
// 5. Accept client
SOCKET client = accept(listener, NULL, NULL); // waits for connection
std::cout << "Established connection from " << client << std::endl;
if (client != INVALID_SOCKET) {
closesocket(listener);
WSACleanup();
}
// 6. Encode frame:
cv::Mat frame = cv::imread("../../data/img_sample.jpg");
std::vector<uchar> buf(50000);
cv::imencode(".jpg", frame, buf);
// Decoding the buffer here results in original image without issues
// cv::Mat frame2 = cv::imdecode(cv::Mat(buf), 1);
size_t buffer_size = buf.size();
// 7. Send encoded frame
//while (true) {
send(client, (char*)(&buffer_size), sizeof(buffer_size), 0);
size_t remain = buffer_size;
size_t offset = 0;
int len;
while ((remain > 0) && ((len = send(client, (char*)(buf.data()) + offset, remain, 0)) > 0))
{
remain -= len;
offset += len;
}
if (len <= 0)
{
std::cout << "Encoding error" << std::endl;
}
//send(m_clients[i], reinterpret_cast<char*>(buf.data()), buffer_size, 0);
//}
closesocket(client);
return 0;
}
// ~~~~~~~~~~~~~~~~~~~~ Code Client: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include <ws2tcpip.h>
include <string>
include <vector>
include <opencv2 core="" core.hpp="">
include <opencv2 highgui="" highgui.hpp="">
include <opencv2 imgproc="" imgproc.hpp="">
include <opencv2 opencv.hpp="">
include <opencv2 core="" utils="" trace.hpp="">
int main(int argc, char* argv[])
{
std::string ipAddress = "192.ipAddress.Of.Server";
int port = 54000;
WSADATA data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
std::cerr << "Can't start Winsock, Err #" << wsResult << std::endl;
return 0;
}
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Can't create socket, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return 0;
}
// Fill in a hint structure
sockaddr_in hints;
hints.sin_family = AF_INET;
hints.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hints.sin_addr);
// Connect to server
int connection_result = connect(clientSocket, (sockaddr*)&hints, sizeof(hints));
if (connection_result == SOCKET_ERROR) {
std::cerr << "Can't connect to server, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return 0;
}
char quitProgram = 'n';
cv::Mat frame;
std::vector <char> buffer;
size_t buffer_size = 0;
while (buffer_size == 0) {
recv(clientSocket, (char *)(&buffer_size), sizeof(int), 0);
}
buffer.resize(buffer_size);
std::cout << "buffer.size = " << buffer.size() << std::endl;
int len = 0;
size_t remain = buffer_size;
size_t offset = 0;
//while ((remain > 0) && ((len = recv(clientSocket, reinterpret_cast<char*>(buffer.data()) + offset, remain, 0)) > 0))
while ((remain > 0) && ((len = recv(clientSocket, buffer.data() + offset, remain, 0)) > 0))
{
remain -= len;
offset += len;
}
if (len <= 0)
{
std::cout << "Error processing receipt of packet" << std::endl;
// handle fatal error
}
std::vector <char> buffer_uchar;
//buffer_uchar.resize(buffer_size);
std::copy(buffer.begin(), buffer.end(), std::back_inserter(buffer_uchar));
// Buffer is full here
frame = cv::imdecode(cv::Mat(buffer_uchar), 1); // "If the buffer is too short or contains invalid data, the empty matrix will be returned."
// Mat is empty after decoding buffer here
cv::imshow("received frame", frame); // See http://opencv.jp/opencv-2svn_org/cpp/reading_and_writing_images_and_video.html
quitProgram = cv::waitKey(100);
if (quitProgram == 'q') {
closesocket(clientSocket);
WSACleanup();
}
}