VC++与java进行socket通讯

近期在做一个视频采集传输的项目,使用到了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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值