客戶端用C發送文件到Java服務器

前言

在寫客戶端發送文件到Java服務器的時候,一是遇到了Netty接收默認字節長度的問題,Netty默認的接收長度是1024,這個問題通過DelimiterBasedFrameDecoder解決。二是我一開始除了應用DelimiterBasedFrameDecoder之外,還應用了StringDecoder,結果在Handler裏(繼承自ChannelHandlerAdapter),接收到的object是String,然後通過String.getBytes()獲得的字節流的長度總是和原文件的長度不同(通過notepad++查看)。隨後,我把StringDecoder去掉了,只用DelimiterBasedFrameDecoder就可以了。

其中C端,我用的Windows上的零拷貝函數TransmitFile(),因爲是通過字節流寫文件的,所以如果通過記事本打開的文件包含中文的話會出現亂碼問題。

源程序

客戶端(C):

VS2019,Debug,Win32

#include <stdio.h>
#include <stdlib.h>

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

#include <MSWSock.h>
#pragma comment(lib, "Mswsock.lib ")

int sendFile()
{
	const wchar_t* fileName = L"D:/writeJson.txt";
	const char* ip = "127.0.0.1";
	const char* port = "8080";
	

	// 創建並初始化winsock數據變量
	WSADATA wsaData = { 0 };
	int iResult = 0;

	SOCKET hSocket = INVALID_SOCKET;
	int iFamily = AF_INET;
	int iType = SOCK_STREAM;
	int iProtocol = IPPROTO_TCP;

	// 初始化 Winsock
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed: %d\n", iResult);
		return -1;
	}
	// 打開socket
	hSocket = socket(iFamily, iType, iProtocol);
	if (hSocket == INVALID_SOCKET) {
		printf("socket function failed with error = %d\n", WSAGetLastError());
		WSACleanup();
		return -2;
	}

	// 設置遠程段地址
	sockaddr_in remoteAddr;
	remoteAddr.sin_family = AF_INET;
	//remoteAddr.sin_addr.s_addr = inet_addr(v[2]);
	//綁定ip
	inet_pton(AF_INET, ip, &remoteAddr.sin_addr);
	//綁定端口
	remoteAddr.sin_port = htons(atoi(port));
	
	do {
		// 打開文件
		HANDLE hFile = CreateFile((LPCWSTR)fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
		if (hFile == INVALID_HANDLE_VALUE) {
			iResult = -3;
			printf("打開文件失敗");
			break;
		}
		// 獲取文件大小
		//GetFileSize(hFile, NULL);
		LARGE_INTEGER liFileSize;
		if (GetFileSizeEx(hFile, &liFileSize) == FALSE) {
			iResult = -4;
			printf("獲取文件大小失敗");
			break;
		}
		
		// 連接到遠程端
		iResult = connect(hSocket, (SOCKADDR*)&remoteAddr, sizeof(remoteAddr));
		if (iResult == SOCKET_ERROR) {
			printf("connect function failed with error: %ld\n", WSAGetLastError());
			iResult = -5;
			break;
		}
		// 使用TransmitFile發送文件
		if (TransmitFile(hSocket, hFile, 0, 0, NULL, NULL, TF_USE_DEFAULT_WORKER) == FALSE) {
			printf("TransmitFile function failed with error: %ld\n", WSAGetLastError());
			iResult = -6;
			break;
		}
	} while (0);
	const char* endStr = "$_$";
	//發送結尾標識符
	iResult = send(hSocket, endStr, strlen(endStr) + 1, 0);
	if (iResult == SOCKET_ERROR) {
		printf("發送結尾標記失敗\n");
		iResult = -10;
	}
	// 關閉socket
	iResult = closesocket(hSocket);
	if (iResult == SOCKET_ERROR) {
		printf("closesocket failed with error = %d\n", WSAGetLastError());
		iResult = -7;
	}
	// 清理
	WSACleanup();

	return iResult;
}

服務器端Netty接收(Java):

Netty版本:

監聽端口程序HttpServer.java:

public class HttpServer {
    /**
     * 監聽端口
     */
    private static int port = 8080;

    public static void main(String[] args) {
        HttpServer httpServer = new HttpServer();
        httpServer.acceptWait();
    }

    /**
     * @Description : Netty監聽數據請求
     * @author : 申劭明
     * @date : 2019/9/17 10:29
     */
    public void acceptWait() {
        //監聽請求
        EventLoopGroup listenGroup = new NioEventLoopGroup();
        //請求處理
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        //綁定監聽請求和處理請求的group
        bootstrap.group(listenGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                //採取靈活的數據長度接收數據,入參爲單位是字節,1<<4<<20表示16MB,發送信息以$_$結尾
                                .addLast(new DelimiterBasedFrameDecoder(1<<4<<20, Unpooled.copiedBuffer("$_$".getBytes())))
                                .addLast(new RequestHandler());
                    }
                });
        ChannelFuture future = null;
        try {
            future = bootstrap.bind(port).sync();
            future.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            listenGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

自己定義的Handler,RequestHandler.java:

public class RequestHandler extends ChannelHandlerAdapter {

    public RequestHandler(){
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.err.println(msg.getClass());
        if (msg instanceof ByteBuf){
            ByteBuf byteBuf = (ByteBuf)msg;
            System.out.println(byteBuf.toString(CharsetUtil.US_ASCII).length());
            if (byteBuf.toString(CharsetUtil.US_ASCII).length() < 10){
                return;
            }

            File file = new File("D:/test.jpg");
            //DMA
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");
            //從文件開頭寫數據
            randomAccessFile.seek(0);
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            System.out.println(bytes.length);
            randomAccessFile.write(bytes);
            randomAccessFile.close();
            ctx.close();
        }else{
            return;
        }

    }

    //    @Override
//    protected void messageReceived(ChannelHandlerContext channelHandlerContext, Object o) {
//        //接收數據
//        Request request = new Request((ByteBuf) o);
//        String receiveMessage = request.getMessage();
//        System.out.println(receiveMessage);
//        if (receiveMessage.contains("\"wxid\":\"gh_")){
//            return;
//        }
//        String receiveMessage = ((ByteBuf)o).toString(CharsetUtil.US_ASCII);
//        System.err.println(receiveMessage);
//
//        channelHandlerContext.close();
//    }


    public static String httpGet(String message){
        HttpClient httpClient = null;
        try {
            URL url = new URL("http://192.168.100.100:9000/cardb/testWord?word=" + message);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setRequestMethod("GET");
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), CharsetUtil.UTF_8));
            String line = null;
            StringBuilder result = new StringBuilder();
            while ((line = br.readLine()) != null){
                result.append(line);
            }
            connection.disconnect();
            System.err.println(result);
            JSONObject jsonObject = new JSONObject(result.toString());
            return jsonObject.get("data").toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (httpClient != null){
                httpClient.closeServer();
            }
        }
        return null;
    }

    private static String httpGet(Message message){
        return httpGet(message.getContent());
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章