VC++与java进行socket通讯

本文详细介绍了使用VC++进行视频采集,通过Socket数据传输到Java服务端的过程。涉及到的关键技术包括海康威视的API接口,图像数据的编码和解码,以及Java的线程池处理客户端连接。在Java端,接收到图像数据后将其保存为JPEG图片文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近期在做一个视频采集传输的项目,使用到了VC++与Java的Socket数据传输,将其要点记录下来,以备查询。

  1. VC端
int err;
WORD versionRequired;
WSADATA wsaData;
versionRequired=MAKEWORD(1,1);
err=WSAStartup(versionRequired,&wsaData);//协议库的版本信息
if (!err)    {
	printf("客户端嵌套字已经打开!\n");
}else{
	printf("ERROR:客户端的嵌套字打开失败!\n");
	AfxMessageBox("ERROR:客户端的嵌套字打开失败!\n");
	return 1;//结束
}
SendPicInfo m_sendPicInfo;
//这里的缓冲区大小需要根据抓图的分辨率大小自己调节,建议设置成2*图片的分辨率宽*图片的分辨率高
char * Jpeg = new char[352*288*2]; 
DWORD len = 352*288*2; 
DWORD SizeReturned = 0;
		
SSOCXInfo* pInfo = (SSOCXInfo*) lpParam;
// Jpeg结构参数
NET_DVR_JPEGPARA struJpegPara;
memset(&struJpegPara, 0, sizeof(NET_DVR_JPEGPARA));
struJpegPara.wPicQuality = 0;
//struJpegPara.wPicSize = (WORD) 0;
struJpegPara.wPicSize =  0xff;	

SOCKADDR_IN clientsock_in;
				clientsock_in.sin_addr.S_un.S_addr=inet_addr("192.168.1.160");
clientsock_in.sin_family=AF_INET;
clientsock_in.sin_port=htons(8765);		

// 调用海康威视接口,截取摄像头图像
if (NET_DVR_CaptureJPEGPicture_NEW(i,1,&struJpegPara, Jpeg, len, &SizeReturned))
{
	// 保存为文件
	//FILE *file=NULL;
	//file = fopen("d:/test/库文件/11.jpg" ,"wb");
	//fwrite(Jpeg, SizeReturned, 1, file);
	//fclose(file);
	//file=NULL;

	//char * imgLen = new char[sizeof(DWORD)];
	memcpy(&m_sendPicInfo.dataLength, &SizeReturned,sizeof(DWORD));
	memcpy(&m_sendPicInfo.cmrIp, pInfo->saveFile, strlen(pInfo->saveFile));

	// 发送到服务器
	SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,0);
	// 建立连接
	connect(clientSocket,(SOCKADDR*) &clientsock_in, sizeof(SOCKADDR));
	// 发送IP及图形数据长度到服务器
	send(clientSocket, (char *)&m_sendPicInfo, sizeof(SendPicInfo), 0);
	Sleep(50);
	// 发送获取到的JPG字节流
	send(clientSocket, Jpeg, SizeReturned, 0);
	Sleep(250);
	
	//测试发送中文字符
	//CString sendStr = "[hello,this is client测试]";
	//send(clientSocket, sendStr, strlen(sendStr),0);c (char *)&sendUser, sizeof(UsrData)

	// 接收服务器端的反馈信息
	//char receiveBuf[100];
	//recv(clientSocket, receiveBuf,101,0);
	//printf("Recv:%s\n",receiveBuf);
	
	closesocket(clientSocket);
	WSACleanup	();
}

结构体

struct GetPicInfo
{
	int		iDeviceIndex;
	LONG	lLoginID;
	CString	chDeviceName;		//device name
	CString	chDeviceIP;
	//CString saveFile;
	HANDLE hMutex;
	HANDLE hThread;
	DWORD ThreadID;
	SSOCXInfo chkInfo;
};

struct SendPicInfo
{
	char dataLength [4];
	char cmrIp[16];
	......
};
  1. JAVA端(服务端)
public void doThing1() {
	try {
		ServerSocket server = new ServerSocket(PORT);
		Socket client = null;
		// 通过调用Executors类的静态方法,创建一个ExecutorService实例
		// ExecutorService接口是Executor接口的子接口
		Executor service = Executors.newCachedThreadPool();

		while (true) {
			// 等待客户端的连接
			client = server.accept();
			//System.out.println("与客户端连接成功!");
			// 调用execute()方法时,如果必要,会创建一个新的线程来处理任务,但它首先会尝试使用已有的线程,
			// 如果一个线程空闲60秒以上,则将其移除线程池;
			// 另外,任务是在Executor的内部排队,而不是在网络中排队
			service.execute(new ServerThread(client));
		}
		server.close();
	} catch (IOException ee) {
		ee.printStackTrace();
	} catch (Exception e) {
		e.printStackTrace();
	}
}

接收线程

package cn.xaele.thread;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.Socket;

import javax.imageio.ImageIO;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import cn.xaele.utils.ByteUtil;

public class ServerThread implements Runnable {

	// 日志输出
	private static final Logger log = LogManager.getLogger(ServerThread.class);

	private Socket client = null;
	private static boolean isTest = false;

	public ServerThread(Socket client) {
		this.client = client;
	}

	// 处理通信细节的静态方法,这里主要是方便线程池服务器的调用
	public static void execute(Socket client) {
		int tmpNum = (int) (Math.random() * 1000);
		if (isTest) {
			log.info(tmpNum + "----------->进入线程");
		}
		try {
			long startTime = System.currentTimeMillis();
			// 获取Socket的输出流,用来向客户端发送数据
			DataInputStream dis = new DataInputStream(client.getInputStream());

			int len = 0;
			byte[] buffer = new byte[1024];

			len = dis.read(buffer, 0, 20);
			if (isTest) {
				System.out.println("读取字节长度[" + len + "]");
			}

			byte[] dataLength = new byte[4];
			System.arraycopy(buffer, 0, dataLength, 0, 4);
			long picLength = ByteUtil.bytesToLong(dataLength);
			if (isTest) {
				System.out.println("图形字节长度[" + picLength + "]");
			}

			byte[] cmrIp = new byte[16];
			System.arraycopy(buffer, 4, cmrIp, 0, 16);
			// 对VC上传的字节进行转码,防止中文乱码
			String cmpIpStr = new String(cmrIp, "GB2312").trim();
			if (isTest) {
				System.out.println("[" + cmpIpStr + "]");
			}

			// 读取VC上传的jpg图形字节流
			buffer = new byte[(int) picLength];
			len = dis.read(buffer, 0, (int) picLength);

			if (isTest) {
				System.out.println("读取长度[" + buffer.length + "]");
			}
			ByteArrayInputStream in = new ByteArrayInputStream(buffer); // 将buffer作为输入流;
			BufferedImage image = ImageIO.read(in); // 将in作为输入流,读取图片存入image中,而这里in可以为ByteArrayInputStream();

			ImageIO.write((BufferedImage) image, "JPEG", new File("d:/" + cmpIpStr + ".jpg"));

			in.close();
			if (isTest) {
			log.info("耗时:[" + (System.currentTimeMillis() - startTime) + "]ms");
			}
			dis.close();
			client.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			log.info(tmpNum + "--------->退出线程");
		}
	}

	@Override
	public void run() {
		execute(client);
	}

}

3.注意事项
3.1 在Java中对需要进行socket传递的内容按照C++格式进行转码。常用代码如下:

public static int bytesToInt(byte[] b) {
	int s = 0;
	for (int i = 3; i > -1; i--) {
		s *= 256;
		s += b[i] < 0 ? b[i] + 256 : b[i];
	}
	return s;
}

public static int bytesToInt(char[] b) {
	int s = 0;
	for (int i = 3; i > -1; i--) {
		s *= 256;
		s += b[i] < 0 ? b[i] + 256 : b[i];
	}
	return s;
}

public static byte[] intToBytes(int n) {
	byte[] b = new byte[4];
	b[0] = (byte) (n & 0xff);
	b[1] = (byte) (n >> 8 & 0xff);
	b[2] = (byte) (n >> 16 & 0xff);
	b[3] = (byte) (n >> 24 & 0xff);
	return b;
}

public static char[] intToChars(int n) {
	char[] b = new char[4];
	b[0] = (char) (n & 0xff);
	b[1] = (char) (n >> 8 & 0xff);
	b[2] = (char) (n >> 16 & 0xff);
	b[3] = (char) (n >> 24 & 0xff);
	return b;
}

public static long bytesToLong(byte[] b) {
	int s = 0;
	for (int i = 3; i > -1; i--) {
		s *= 256;
		s += b[i] < 0 ? b[i] + 256 : b[i];
	}
	return s;
}

public static long bytesToLong(char[] b) {
	int s = 0;
	for (int i = 3; i > -1; i--) {
		s *= 256;
		s += b[i] < 0 ? b[i] + 256 : b[i];
	}
	return s;
}

public static byte[] longToBytes(long n) {
	byte[] b = new byte[4];
	b[0] = (byte) (n & 0xff);
	b[1] = (byte) (n >> 8 & 0xff);
	b[2] = (byte) (n >> 16 & 0xff);
	b[3] = (byte) (n >> 24 & 0xff);
	return b;
}

public static float bytesToFloat(byte[] b) {
	int num = bytesToInt(b);
	return Float.intBitsToFloat(num);
}

public static float bytesToFloat(char[] b) {
	int num = bytesToInt(b);
	return Float.intBitsToFloat(num);
}

public static byte[] floatToBytes(float f) {
	return intToBytes(Float.floatToRawIntBits(f));
}

public static double bytesToDouble(byte[] b) {
	long num = bytesToLong(b);
	return Double.longBitsToDouble(num);
}

public static byte[] doubleToBytes(double f) {
	return longToBytes(Double.doubleToRawLongBits(f));
}

public static String bytesToString(byte[] b, int length) {
	return new String(b, 0, length);
}

public static byte[] stringToBytes(String s, int length) {
	while (s.getBytes().length < length)
		s += "\0";
	return s.getBytes();
}

public static String toHexString(int num) {
	String tmp = (java.lang.Integer.toHexString((char) num & 0XFF));
	return (tmp.length() == 1) ? "0" + tmp : tmp;
}

/**
 * java字节码转字符串
 * 
 * @param b
 * @return
 */
public static String printByte(char[] b) { // 一个字节的数,// 转成16进制字符串
	String hs = "";
	String tmp = "";
	for (int n = 0; n < b.length; n++) {
		// 整数转成十六进制表示
		tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
		if (tmp.length() == 1) {
			hs = hs + "0" + tmp + " ";
		} else {
			hs = hs + tmp + " ";
		}
	}

	tmp = null;
	return hs.toUpperCase(); // 转成大写
}

/**
 * java字节码转字符串
 * 
 * @param b
 * @return
 */
public static String printByte(byte[] b) { // 一个字节的数,// 转成16进制字符串
	String hs = "";
	String tmp = "";
	for (int n = 0; n < b.length; n++) {
		// 整数转成十六进制表示
		tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
		if (tmp.length() == 1) {
			hs = hs + "0" + tmp + " ";
		} else {
			hs = hs + tmp + " ";
		}
	}

	tmp = null;
	return hs.toUpperCase(); // 转成大写
}

/**
 * java字节码转字符串
 * 
 * @param b
 * @return
 */
public static String printByte(int[] b) { // 一个字节的数,// 转成16进制字符串
	String hs = "";
	String tmp = "";
	for (int n = 0; n < b.length; n++) {
		// 整数转成十六进制表示
		tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
		if (tmp.length() == 1) {
			hs = hs + "0" + tmp + " ";
		} else {
			hs = hs + tmp + " ";
		}
	}

	tmp = null;
	return hs.toUpperCase(); // 转成大写
}

/**
 * int转byte
 * 
 * @param x
 * @return
 */
public static byte intToByte(int x) {
	return (byte) x;
}

/**
 * byte转int
 * 
 * @param b
 * @return
 */
public static int byteToInt(byte b) {
	// Java的byte是有符号,通过 &0xFF转为无符号
	return b & 0xFF;
}

/**
 * byte[]转int
 * 
 * @param b
 * @return
 */
public static int byteArrayToInt(byte[] b) {
	return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16 | (b[0] & 0xFF) << 24;
}

public static int byteArrayToInt(byte[] b, int index) {
	return b[index + 3] & 0xFF | (b[index + 2] & 0xFF) << 8 | (b[index + 1] & 0xFF) << 16
			| (b[index + 0] & 0xFF) << 24;
}

/**
 * int转byte[]
 * 
 * @param a
 * @return
 */
public static byte[] intToByteArray(int a) {
	return new byte[] { (byte) ((a >> 24) & 0xFF), (byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF),
			(byte) (a & 0xFF) };
}

/**
 * short转byte[]
 * 
 * @param b
 * @param s
 * @param index
 */
public static void byteArrToShort(byte b[], short s, int index) {
	b[index + 1] = (byte) (s >> 8);
	b[index + 0] = (byte) (s >> 0);
}

/**
 * byte[]转short
 * 
 * @param b
 * @param index
 * @return
 */
public static short byteArrToShort(byte[] b, int index) {
	return (short) (((b[index + 0] << 8) | b[index + 1] & 0xff));
}

/**
 * 16位short转byte[]
 * 
 * @param s
 *            short
 * @return byte[]
 */
public static byte[] shortToByteArr(short s) {
	byte[] targets = new byte[2];
	for (int i = 0; i < 2; i++) {
		int offset = (targets.length - 1 - i) * 8;
		targets[i] = (byte) ((s >>> offset) & 0xff);
	}
	return targets;
}

/**
 * byte[]转16位short
 * 
 * @param b
 * @return
 */
public static short byteArrToShort(byte[] b) {
	return byteArrToShort(b, 0);
}

/**
 * long转byte[]
 * 
 * @param x
 * @return
 */
public static byte[] longToBytes1(long x) {
	buffer.putLong(0, x);
	return buffer.array();
}

/**
 * byte[]转Long
 * 
 * @param bytes
 * @return
 */
public static long bytesToLong1(byte[] bytes) {
	buffer.put(bytes, 0, bytes.length);
	buffer.flip();// need flip
	return buffer.getLong();
}

/**
 * 从byte[]中抽取新的byte[]
 * 
 * @param data
 *            - 元数据
 * @param start
 *            - 开始位置
 * @param end
 *            - 结束位置
 * @return 新byte[]
 */
public static byte[] getByteArr(byte[] data, int start, int end) {
	byte[] ret = new byte[end - start];
	for (int i = 0; (start + i) < end; i++) {
		ret[i] = data[start + i];
	}
	return ret;
}

/**
 * 流转换为byte[]
 * 
 * @param inStream
 * @return
 */
public static byte[] readInputStream(InputStream inStream) {
	ByteArrayOutputStream outStream = null;
	try {
		outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		byte[] data = null;
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		data = outStream.toByteArray();
		return data;
	} catch (IOException e) {
		return null;
	} finally {
		try {
			if (outStream != null) {
				outStream.close();
			}
			if (inStream != null) {
				inStream.close();
			}
		} catch (IOException e) {
			return null;
		}
	}
}

/**
 * byte[]转inputstream
 * 
 * @param b
 * @return
 */
public static InputStream readByteArr(byte[] b) {
	return new ByteArrayInputStream(b);
}

/**
 * byte数组内数字是否相同
 * 
 * @param s1
 * @param s2
 * @return
 */
public static boolean isEq(byte[] s1, byte[] s2) {
	int slen = s1.length;
	if (slen == s2.length) {
		for (int index = 0; index < slen; index++) {
			if (s1[index] != s2[index]) {
				return false;
			}
		}
		return true;
	}
	return false;
}

/**
 * byte数组转换为Stirng
 * 
 * @param s1
 *            -数组
 * @param encode
 *            -字符集
 * @param err
 *            -转换错误时返回该文字
 * @return
 */
public static String getString(byte[] s1, String encode, String err) {
	try {
		return new String(s1, encode);
	} catch (UnsupportedEncodingException e) {
		return err == null ? null : err;
	}
}

/**
 * byte数组转换为Stirng
 * 
 * @param s1-数组
 * @param encode-字符集
 * @return
 */
public static String getString(byte[] s1, String encode) {
	return getString(s1, encode, null);
}

/**
 * 字节数组转16进制字符串
 * 
 * @param b
 * @return
 */
public static String byteArrToHexString(byte[] b) {
	String result = "";
	for (int i = 0; i < b.length; i++) {
		result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
	}
	return result;
}

/**
 * 16进制字符创转int
 * 
 * @param hexString
 * @return
 */
public static int hexStringToInt(String hexString) {
	return Integer.parseInt(hexString, 16);
}

/**
 * 十进制转二进制
 * 
 * @param i
 * @return
 */
public static String intToBinary(int i) {
	return Integer.toBinaryString(i);
}

3.2 对于大数据量传输,需要分两次,第一次传送基本信息,并在其中指定待传数据长度(及其传递次数,如果有必要的话);第二次传送大数据信息(或按照第一次的约定多次传输),在接收端进行组装。
3.3 如果传递的字节长度较大,且需多次传输,建议使用ByteArrayOutputStream bo = new ByteArrayOutputStream(1024);

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值