我已经在网上引用了一些tutoials并编写了一个Android应用程序。应用程序应该向服务器发送命令,然后服务器响应消息(命令和响应是字符方式)。之后我的应用程序会将一些文件发送到服务器。所有这些都通过TCP连接进行通信。我已经使用一些PC TCP测试软件对其进行了测试,但并不总是成功发送完整的文件。有时TCP测试工具会挂起并弹出一些错误消息。我不知道这是PC工具还是我的应用程序的问题。
事实上我还有另外两个问题。一个是我不知道什么时候应该关闭套接字。在教程中它关闭"最后"例行公事,好吗?实际上什么时候会被关闭?我希望在发出所有文件后将其关闭。
另一个问题是我仍然无法收到从服务器发回的响应消息。
我是Android App开发的新手,所以代码可能看起来很傻,请指导我并告诉我任何问题,非常感谢。
以下是我的代码: 我将TCP客户端实现为异步任务
public class TCPClient {
public static final String SERVERIP = "192.168.0.100"; //Server's IP address
public static final int SERVERPORT = 4444; // Server's listening port
private Socket socket;
private OnMessageReceived mMessageListener = null;
private boolean mRun = false;
private static final String TAG = "TCPClient";
PrintWriter out;
BufferedReader in;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TCPClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends message out
* @param message text (ASCII string) to be send out
*/
public void sendMessage(String message){
Log.d(TAG, "Sent Message: " + message);
if (out != null && !out.checkError()) {
out.println(message);
out.flush();
}
}
/**
* Send file out
*/
public void sendFile(String filepath){
try {
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
if(bos != null){
File myFile = new File( filepath );
byte[] mybytearray = new byte[(int) myFile.length()];
// Create InputStream object from the file
FileInputStream fis = null;
try {
fis = new FileInputStream(myFile);
} catch (FileNotFoundException ex) {
// Do exception handling
}
// Try to copy data from InputStream (file) to OutputStream (TCP socket)
try {
int count;
BufferedInputStream bis = new BufferedInputStream(fis);
while ( (count = bis.read(mybytearray)) > -1 ){
bos.write(mybytearray, 0, count);
}
} catch (IOException ex) {
// Do exception handling
}
bos.flush();
bos.close();
}
} catch (IOException ex) {
// Do exception handling
}
}
public void stopClient(){
Log.d(TAG, "Client stopped!");
mRun = false;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
Log.d(TAG, "C: Connecting...");
//create a socket to make the connection with the server
socket = new Socket(serverAddr, SERVERPORT);
Log.d(TAG, "TCP connected");
try {
// A "Writer" for sending our command/message to the socket
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
// A "Reader" for read back the response from the server
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.d(TAG, "In/Out created");
//in this while the client listens for the messages sent by the server
while (mRun) {
serverMessage = in.readLine();
if (serverMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(serverMessage);
}
serverMessage = null;
}
Log.d(TAG, "S: Received Message: '" + serverMessage + "'");
} catch (Exception e) {
Log.e(TAG, "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
Log.d(TAG, "Close socket");
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
//class at on asynckTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
这是连接到服务器的异步任务(我在MainActivity.java中实现了它)
public class connectTask extends AsyncTask<String,String,TCPClient> {
@Override
protected TCPClient doInBackground(String... message) {
Log.d(TAG, "In do in background");
//we create a TCPClient object and
mTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
@Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
Log.d(TAG, "message received");
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
// When received message from server, do something here...
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
Log.d(TAG, "In progress update, values: " + values.toString());
}
}
当我想连接到服务器时:
new connectTask().execute("");
当我想发送文件时,我会调用&#34; send_my_file()&#34; MainActivity.java中的方法:
public static String test_filepath;
test_filepath = externalStoragePublicDirectory.getPath() + "/test.wav";
send_my_file(test_filepath);
public void send_my_file(String filepath)
{
if (mTcpClient != null) {
Log.d(TAG, "Start Send File");
mTcpClient.sendFile(filepath);
}
}
更新:
1。)由于它被标记为重复,我想澄清一下,我问的是为什么只有部分文件被发送到 TCP通道,但没有问为什么从套接字正确接收多个文件。
2。)感谢@EJP,他给了我相关排队的链接。我在那里参考答案并回顾了BufferedInputStream的read()的用法。我发现我误解了read(myFile)方法的用法,它会从文件中返回一个字节。最初我以为它会读取整个文件并将其存储在缓冲区中。相反,我应该使用read(buffer,0,fileSize),它将读取文件并将其中的一部分存储到缓冲区。另外为了提高效率,我实际上应该使用较小的缓冲区而不是创建与文件大小相同的缓冲区。我现在可以成功发送整个文件。修复是:
fileSize = myFile.length();
byte[] mybytearray = new byte[8192];
while ( fileSize > 0 && (count = bis.read(mybytearray, 0, (int)Math.min(mybytearray.length, fileSize)) ) > -1 ){
bos.write(mybytearray, 0, count);
fileSize -= count;
}