通过socket实现c++发送图片,python接收图片并展示(基于UDP)

如题,话不多说,贴代码:

C++发送:

// sendImage.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

using namespace std;

SOCKET createSocket();	
void openPicture(char data[], FILE* &p);


struct Picture {
	char buffer[4096];  //用于发送数据缓冲区
}picture; 

int _tmain(int argc, _TCHAR* argv[])
{
	SOCKET client = createSocket();
	
	sockaddr_in saddr;

	//接收端地址长度
	int slen = sizeof(saddr);
	//目的地址
	//设置服务器地址
	saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
	saddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	char data[100] = { 0 };                    //接受一些短字节的数据缓冲区
	char begin[] = "I BEGIN";       //发送图片前的确认信息
	char end[] = "I FINISHED";         //完成图片发送的通知信息

	int iSend = 0;                             //发送函数的状态
	FILE *p;                                   //创建一个文件指针

		
	//发送图片前先和服务器打个招呼,欲准备状态,判断信息发送是否成功,若不成功,则服务器处于关闭状态
	iSend = sendto(client, begin, strlen(begin), 0, (SOCKADDR*)&saddr, slen);

	if (iSend == SOCKET_ERROR) {  
			cout << "服务器处于关闭状态,请稍后重试!" << endl;   
			cout << "20s后退出控制台!" << endl;
			closesocket(client);
			WSACleanup();
			Sleep(20000);
			return -4;
	}
	cout << "Client: " << begin << endl;

	memset(data, 0, sizeof(data));

	openPicture(data,p);  
	fseek(p, 0, SEEK_END);
	int length = ftell(p);  //获取图片总长度
	fseek(p, 0, SEEK_SET);  //指针还原到开始位置
	cout << "Img length: " << length << endl;

	iSend = sendto(client, (char *)&length, sizeof(int), 0, (SOCKADDR*)&saddr, slen); //首先发送图片大小(单位byte)给接收端
	if (iSend == SOCKET_ERROR) {  
			cout << "文件长度信息发送失败!" << endl;   
			cout << "10s后退出控制台!" << endl;
			closesocket(client);
			WSACleanup();
			Sleep(10000);
			return -4;
	}

	cout <<endl;
	cout << "····BEGIN SEND PICTURE····" << endl;
	int i = 1;

	while (length > 0) {
			cout << i << endl;
			
			memset(picture.buffer, 0, sizeof(picture.buffer));     //初始化接受缓冲区
			fread(picture.buffer, sizeof(picture.buffer), 1, p);     //读取图片到缓冲区

			int len = sizeof(picture.buffer);                      //获取读取的长度
			
            /*若读取的长度大于当前图片剩余总长度,将结构体的图片长度赋值为图片剩余长度,
			并标记图片读取结束;否则图片长度为读取缓冲区长度,图片标记状态为未完成 */

			//发送图片的一部分,发送成功,则图片总长度减去当前发送的图片长度
			iSend = sendto(client, (char*)&picture, sizeof(struct Picture), 0, (SOCKADDR*)&saddr, slen);

			if (iSend == SOCKET_ERROR) {
				cout << "发送图片出错" << endl;
				cout << "2s后退出控制台!" << endl;
				closesocket(client);
				WSACleanup();
				Sleep(2000);
				return -8;
			}
			
			length -= len;
			i++;
	}

	fclose(p);
	p = NULL;
	closesocket(client);
	WSACleanup();
	cout<< "SEND FINISH" << endl;
	cin.get();
	return 0;
}



SOCKET createSocket() {
	//声明调用不同的Winsock版本。
	WORD version = MAKEWORD(2, 2);
	//一种数据结构。这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。
	WSADATA wsadata;
	/*WSAStartup必须是应用程序或DLL调用的第一个Windows Sockets函数。
	它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节。
	应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。
    */
	if (WSAStartup(version, &wsadata))
	{
		cout << "WSAStartup failed " << endl;
		cout << "2s后控制台将会关闭!" << endl;
		Sleep(2000);
		exit(0);
	}
	//判断版本
	if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2)
	{
		cout << "wVersion not 2.2" << endl;
		cout << "2s后控制台将会关闭!" << endl;
		Sleep(2000);
		exit(0);
	}
	//创建客户端UDP套接字
	SOCKET client;
	client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (SOCKET_ERROR == client)
	{
		cout << "socket failed" << endl;
		cout << "2s后控制台将会关闭!" << endl;
		Sleep(2000);
		exit(0);
	}
	else {
		return client;
	}
}


void openPicture(char data[],FILE* &p) {
	while (1) {
		cout << "请输入要发送图片的路径: " << endl;
		cin >> data;  //输入图片的绝对路径
		// 以读 / 写方式打开一个二进制文件,只允许读 / 写数据。若图片无法打开,则路径有问题,关闭连接
		if (!(p = fopen(data, "rb+"))) {
			memset(data, 0, sizeof(data));
			cout << "图片路径出错,请重新尝试!" << endl;
		}
		else {
			break;
		}
	}
}

python接收并显示:

import socket
import struct
import cv2
import numpy as np

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',9999))
print("waiting...")

data, addr = server.recvfrom(256) #shoud be b'I BEGIN'
print(str(data)+" from "+str(addr))

data, addr = server.recvfrom(16)
#print(data)
#img_size = struct.unpack(">L", data)[0]
img_size = int.from_bytes(data, byteorder = 'little') #img size, (bytes)
#print(img_size)

img_recv_all = b''
recvd_size = 0
#'''
while True:
    data, addr = server.recvfrom(4096) #阻塞等待数据(value,(ip,port))
    #print(img_file)

    img_recv_all += data
    recvd_size += len(data)
    
    if recvd_size >= img_size:
        break
#'''

img_nparr = np.fromstring(img_recv_all, np.uint8)
img_decoded = cv2.imdecode(img_nparr, cv2.IMREAD_COLOR)
cv2.imshow("WHAT YOU GET", img_decoded)
cv2.waitKey()

cv2.destroyAllWindows()

测试时,先运行python,再运行C,即可。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值