Java客户端上传图片(文件)到c++服务器
2016-09-15 11:44
696 查看
参考自:http://blog.csdn.net/nupt123456789/article/details/8047619
Java客户端上传图片(文件)到c++服务器
主要思路:将所有的数据类型都转化为byte流,对byte进行传输,c++服务器使用char数组,java使用byte数组进行图片(文件)的传输。
传输过程(socket建立连接的条件下):
C++服务器
TAG.h
SocketHead.h
CPlusServer.cpp
Java客户端
Client.java
NetDataCommand.java
NetDataTypeTransform.java
SendFileThread.java
作为菜鸟,在写这个东西的时候遇到了很多问题,我把遇到问题的都写下来了,相信这些是很多新手都可能会遇到的问题
问题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);
点击打开链接下载源代码
Java客户端上传图片(文件)到c++服务器
主要思路:将所有的数据类型都转化为byte流,对byte进行传输,c++服务器使用char数组,java使用byte数组进行图片(文件)的传输。
传输过程(socket建立连接的条件下):
C++服务器
TAG.h
#pragma once #define _TAG_H_ #ifdef _TAG_H_ #include<Windows.h> #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 <winsock2.h> 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<string> #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"<<endl; } } } sockaddr_in initSockaddr_in() { sockaddr_in sockaddr_in; int port = 8888; sockaddr_in.sin_family = AF_INET; sockaddr_in.sin_port = htons(port);//主机字节序转网络字节序 sockaddr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY); return sockaddr_in; } DWORD WINAPI SListen(LPVOID lparam) { SOCKET socket = (SOCKET)lparam; COMMAND command; while (true) { memset(&command, 0, sizeof(command)); int ret; ret = recv(socket, (char*)&command, sizeof(command), 0); if (ret == SOCKET_ERROR) { cout << "Client is close!"<<endl; break; } else{ cout << "接收到命令:" << command.ID << endl; switch (command.ID) { case FileInfo: break; case SendFile: { char* str = (char*)command.lparam; cout << "原文件名" << str<< endl; //开始接收文件 recvFile(socket); } break; case StopSendFile: break; case SendString: break; default: break; } } } return 0; } void recvFile(SOCKET socket) { int ret; char buffer[BUF_LEN]; //接收文件长度 long long fileLenght; ret = recv(socket, (char*)&fileLenght, sizeof(fileLenght), 0); if (ret == SOCKET_ERROR) { cout << "接收文件长度失败" << endl; return; } cout << "文件长度为:" << fileLenght << endl; //告诉客户端可以发送文件了 bool isOk = true; ret = send(socket, (char*)&isOk, sizeof(isOk), 0); if (ret == SOCKET_ERROR) { cout << "发送确认信息失败" << endl; return; } //文件路径 char fileName[20]; string filePath; SYSTEMTIME sys; GetLocalTime(&sys); sprintf_s(fileName, "%04d%02d%02d%02d%02d%02d.jpg", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond); filePath = "F:\\Android\\"; filePath += fileName; //打开文件 ofstream outfile; outfile.open(filePath, ios::out| ios::binary);//传输图片使用二进制格式打开 if (!outfile) { cout << "fail to open file!" << endl; } long recvTotalLen = 0; while (recvTotalLen < fileLenght) { memset(buffer, 0, sizeof(buffer)); ret = recv(socket, buffer, sizeof(buffer), 0); if (ret == SOCKET_ERROR) { cout << "Error:" << GetLastError() << endl; cout << "socket fail when recv file fail !" << endl; break; } outfile.write(buffer, ret); recvTotalLen += ret; cout << "已接收:"<<(recvTotalLen*1.0 / fileLenght*1.0) * 100 << "%" << endl; } if (recvTotalLen == fileLenght) { cout << "recv file success !" << endl; } else { cout << "recv file error !" << endl; } outfile.close(); }
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(); } } }
NetDataCommand.java
package client; public class NetDataCommand { private static final int IDLen=4; private static final int LparamLen=2048; private static final int CommandLen=2052; public byte []byteArrayData=new byte[CommandLen]; private int ID; private String lparam; private NetDataTypeTransform mDataTypeTransform=new NetDataTypeTransform(); public byte[] getByteArrayData(){ return byteArrayData; } public NetDataCommand(){ } public NetDataCommand(int ID,String lparam) { // TODO Auto-generated constructor stub this.ID=ID; this.lparam=lparam; byte[] IDbyte = mDataTypeTransform.IntToByteArray(ID); System.arraycopy(IDbyte,0, byteArrayData, 0, IDbyte.length); byte[] Strbyte = mDataTypeTransform.StringToByteArray(lparam); System.arraycopy(Strbyte,0,byteArrayData,IDbyte.length,Strbyte.length); } public NetDataCommand(int ID,byte[] lparam) { // TODO Auto-generated constructor stub byte[] IDbyte = mDataTypeTransform.IntToByteArray(ID); System.arraycopy(IDbyte,0, byteArrayData, 0, IDbyte.length); byte[] Strbyte =lparam; System.arraycopy(Strbyte,0,byteArrayData,IDbyte.length,Strbyte.length); } public NetDataCommand(byte[] dataArray){ int id=1; String lpString=""; System.arraycopy(dataArray,0, byteArrayData,0,CommandLen); //提取指令id byte[] forIntID = new byte[IDLen]; System.arraycopy(dataArray,0,forIntID,0,forIntID.length); id=mDataTypeTransform.ByteArrayToInt(forIntID); //提取指令内容 byte[] StrTemp=new byte[LparamLen]; System.arraycopy(dataArray,IDLen,StrTemp,0,StrTemp.length); lpString=mDataTypeTransform.ByteArraytoString(StrTemp, StrTemp.length); //lpString=StrTemp.toString(); ID=id; lparam=lpString; } public int getID(){ return ID; } public String getLparam(){ return lparam; } public void setID(int id) { this.ID=id; } public void setLparam(String str){ this.lparam=str; } }
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);
点击打开链接下载源代码
相关文章推荐
- Java学习日记8:文件上传工具类的实现和服务器给客户端发送图片
- ios客户端base64上传图片到java服务器遇到的问题
- JAVA_ 网络编程,写一个可以上传文件的服务器和客户端
- 在C#客户端用HTTP上传文件到Java服务器
- JAVA上传文件图片到指定服务器目录
- Java上传文件图片到服务器的方法
- Java Springboot结合FastDFS实现文件上传以及根据图片url将图片上传至图片服务器
- JAVA上传文件图片到指定服务器目录
- [置顶] JAVA上传文件图片到服务器保存
- fastdfs 图片服务器 使用java端作为客户端上传图片 / 【FastDFS专题】fastdfs使用实战(概念篇)
- (Android)JavaSocket编程,文件上传到服务器,客户端Android,服务器端J2SE
- Java后台服务器接收IOS客户端上传的图片
- Java客户端通过Http发送POST请求上传文件到web服务器
- 多线程实现文件(图片)从客户端并行上传到服务器端--多客户端实现文件上传到服务器
- java使用FTPClient 上传图片文件到服务器
- Java客户端通过Http发送POST请求上传文件到web服务器
- 在C#客户端用HTTP上传文件到Java服务器
- 服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码)
- java FTP方式上传文件到图片服务器
- 在C#客户端用HTTP上传文件到Java服务器