程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Java客戶端上傳圖片(文件)到c++服務器

Java客戶端上傳圖片(文件)到c++服務器

編輯:關於C++

Java客戶端上傳圖片(文件)到c++服務器

主要思路:將所有的數據類型都轉化為byte流,對byte進行傳輸,c++服務器使用char數組,java使用byte數組進行圖片(文件)的傳輸。

傳輸過程(socket建立連接的條件下):

\

C++服務器

TAG.h

 

#pragma once
 
#define _TAG_H_
#ifdef _TAG_H_
 
#include
#define BUF_LEN 2048
 
#define SendFile	0x01
#define StopSendFile	0x02
#define SendString	0x03
#define FileInfo	0x04
 
typedef struct
{
int ID;
BYTE lparam[BUF_LEN];
}COMMAND;
 
typedef struct {
long fileLenght;
char fileName[MAX_PATH];
}FILEINFO;
 
#endif // _TAG_H_

 

SocketHead.h

 

#pragma once
#include 
using namespace std;
#pragma comment(lib, "WS2_32") // 鏈接到WS2_32.lib
 
class CInitSock
{
public:
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if (::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};

CPlusServer.cpp

// CPlusServer.cpp : 定義控制台應用程序的入口點。
//
/*
author:chenjianrun
time:	2016-9-15
city:	zhuhai
*/
#include "stdafx.h"
#include"SocketHead.h"
#include "iostream"
#include "string.h"
#include "fstream"
#include
#include"TAG.h"
using namespace std;
 
//初始化結構體SOCKADDR_IN
sockaddr_in initSockaddr_in();
//監聽線程
DWORD WINAPI SListen(LPVOID lparam);
//接收文件
void recvFile(SOCKET socket);
//初始化socket
void InitSocket();
CInitSock initsocket;
int main()
{
InitSocket();
    return 0;
}
void InitSocket() {
SOCKET serverSocket;
SOCKET listenSocket;
sockaddr_in serveraddr = initSockaddr_in();
sockaddr_in clientaddr;
//創建socket
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//進行綁定
bind(serverSocket, (sockaddr*)&serveraddr, sizeof(serveraddr));
//進行監聽
listen(serverSocket, 5);
 
cout << "server start" << endl;
int len = sizeof(clientaddr);
while (true) {
if (listenSocket = accept(serverSocket, (sockaddr*)&clientaddr, &len));
{
//啟動會話線程
CreateThread(NULL, NULL, SListen, (LPVOID)listenSocket, NULL, NULL);
cout << "CreateThread is start"<

 

Java客戶端

Client.java

/*
author:chenjianrun
time:	2016-9-15
city:	zhuhai
*/
package client;
 
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
 
public class Client {
 
private static NetDataTypeTransform transform1;
private static DataInputStream fromServerStream;
private static DataOutputStream toServerStream;
private static NetDataCommand dataCommand;
private static DataFileInfo dataFileInfo;
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost",8888);
toServerStream = new DataOutputStream(socket.getOutputStream());
//發送要發送文件的指令
int id = 1;
String tempStr = "4.jpg";
dataCommand = new NetDataCommand(id,tempStr);
toServerStream.write(dataCommand.getByteArrayData());
toServerStream.flush();
//啟動發送文件線程
SendFileThread sendFileThread = new SendFileThread(socket);
sendFileThread.start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
 
}

NetDataTypeTransform.java

package client;
 
import java.io.UnsupportedEncodingException;
 
public class NetDataTypeTransform {
public static final String coding="GB2312"; //全局定義,以適應系統其他部分  
    public NetDataTypeTransform(){  
          
    }  
    /**
     * 將int、long轉為低字節在前,高字節在後的byte數組
     */  
    public byte[] IntToByteArray(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 byte[] LongToByteArray(long n) {  
        byte[] b = new byte[8];  
        b[0] = (byte) (n & 0xff);  
        b[1] = (byte) (n >> 8 & 0xff);  
        b[2] = (byte) (n >> 16 & 0xff);  
        b[3] = (byte) (n >> 24 & 0xff);
        b[4] = (byte) (n >> 32 & 0xff);  
        b[5] = (byte) (n >> 40 & 0xff);
        b[6] = (byte) (n >> 48 & 0xff);  
        b[7] = (byte) (n >> 56 & 0xff);
        return b;  
    }
    /**
     * byte數組轉化為int、long
     * 將低字節在前轉為int、long,高字節在後的byte數組
     */  
    public int ByteArrayToInt(byte[] bArr) {  
         if(bArr.length!=4){  
             return -1;  
         }  
         return (int) ((((bArr[3] & 0xff) << 24)    
                    | ((bArr[2] & 0xff) << 16)    
                    | ((bArr[1] & 0xff) << 8) | ((bArr[0] & 0xff) << 0)));   
    }  
    
    public long ByteArrayToLong(byte[] bArr) {  
        if(bArr.length!=8){  
            return -1;  
        }  
        return (long) ((((bArr[7] & 0xff) << 56)
        	| ((bArr[6] & 0xff) << 48)    
                	| ((bArr[5] & 0xff) << 40)
                	| ((bArr[4] & 0xff) << 32)    
                	| ((bArr[3] & 0xff) << 24)
                	| ((bArr[2] & 0xff) << 16)    
                	| ((bArr[1] & 0xff) << 8)
                	| ((bArr[0] & 0xff) << 0)));   
   }
    
    
    
    /**
     * 將byte數組轉化成String,為了支持中文,轉化時用GBK編碼方式
     */  
    public String ByteArraytoString(byte[] valArr,int maxLen) {  
        String result=null;  
        int index = 0;  
        while(index < valArr.length && index < maxLen) {  
            if(valArr[index] == 0) {  
                break;  
            }  
            index++;  
        }  
        byte[] temp = new byte[index];  
        System.arraycopy(valArr, 0, temp, 0, index);  
        try {  
            result= new String(temp,"GBK");  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
    /**
     * 將String轉化為byte,為了支持中文,轉化時用GBK編碼方式
     */  
    public byte[] StringToByteArray(String str){  
        byte[] temp = null;  
        try {  
            temp = str.getBytes("GBK");  
        } catch (UnsupportedEncodingException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        return temp;  
    }  
}

SendFileThread.java

package client;
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
 
public class SendFileThread extends Thread implements Runnable{
 
private Socket socket;
private NetDataCommand dataCommand;
private NetDataTypeTransform transform = new NetDataTypeTransform();
public SendFileThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
DataInputStream fromServerStream = new DataInputStream(socket.getInputStream());
DataOutputStream toServerStream = new DataOutputStream(socket.getOutputStream());
//初始化文件信息
File file = new File("F:\\Android\\4.jpg");
FileInputStream fileInputStream = new FileInputStream(file);
int fileLen = (int)file.length();
//1.發送文件的長度
//toServerStream.write(transform.IntToByteArray(fileLen));
toServerStream.write(transform.LongToByteArray(file.length()));
toServerStream.flush();
//2.確認服務器端已經做好准備
Boolean isOk;
isOk = fromServerStream.readBoolean();
System.out.println(isOk);
byte[] toServerByte = new byte[2048];
int len;//每次發送長度
long sendLen=0;//已經發送的總長度
while((len = fileInputStream.read(toServerByte))>0){
toServerStream.write(toServerByte,0,len);
toServerStream.flush();
sendLen+=len;
System.out.println("len = "+len);
System.out.println("發送進度:"+sendLen*1.0/fileLen*1.0*100+"%");
}
//System.out.println(toServerByte.length);
sleep(10);
if (sendLen == fileLen) {
System.out.println("success");
}
System.out.println("send over!");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
 
}

作為菜鳥,在寫這個東西的時候遇到了很多問題,我把遇到問題的都寫下來了,相信這些是很多新手都可能會遇到的問題

問題1:

在使用txt文件進行測試傳輸時,文件出現了亂碼的情況

分析:

在c++的輸出中outfile.write(buffer, ret)寫文件和outfile <<寫文件是有區別的,outfile.write(buffer, ret)通過形參控制可以寫一個數據塊,比如結構體、數組什麼的;而

outfile << 只能寫基本類型,如int、float、string;如果是outfile <<來寫一個數據塊的話,那麼就會出現問題。

解決方法:

將原先使用outfile << buffer;語句寫文件修改為outfile.write(buffer, ret)進行寫文件。

問題2:

C++服務器接收文件完畢之後,接收到的文件大小大於java客戶端發送過來的文件長度

分析:

我們不管是在c++還是java中,使用socket發送數據時,我們指定發送的長度應該是發送數據的實際長度,而不是buffer的字節數。

解決方法:

在java客戶端中,修改前,我的發送文件時指定的發送長度為toServerByte.length

while((len = fileInputStream.read(toServerByte))>0){

toServerStream.write(toServerByte,0,toServerByte.length);

toServerStream.flush();

}

在java客戶端中,修改後,發送文件時指定長度為len

while((len = fileInputStream.read(toServerByte))>0){

toServerStream.write(toServerByte,0,len);

toServerStream.flush();

}

問題3:

接收到的文件總莫名的多了4個byte,致使接收的圖片不能正常打開。

分析:

c++中long類型是4個byte的,而java中long是8個byte的,每次java中發送的文件長度是long類型,有8個byte,c++服務器接收文件長度時只是從socket緩沖區中copy了4個byte,未被copy的4個byte還放在緩沖區中,因此下次調用recv()函數時就會將其和文件內容一起copy到buffer中寫入文件,也就導致了文件多出4個byte,出現異常。

解決方法:

在c++服務器中將long類型的fileLenght改為long long

未改前

long fileLenght;

ret = recv(socket, (char*)&fileLenght, sizeof(fileLenght), 0);

修改後

long long fileLenght;

ret = recv(socket, (char*)&fileLenght, sizeof(fileLenght), 0);

問題4:

C++服務器中文件全部接收完畢,但是圖片不能打開

分析:

圖片是二進制文件,如果我們是已普通的文件格式打開文件,那麼我們的圖片將不能正常的打開。

解決方法:

以二進制文件格式打開文件

ofstream outfile;

//傳輸圖片使用二進制格式打開

outfile.open(filePath, ios::out| ios::binary);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved