Android TCP客户端发送数据,但TCP服务器接收空数据
我的应用程序中有一个TCP客户端和一个TCP服务器类。 客户端发送小字符串,如“1 | 2 |”或“1 | 11 |” 客户端类Android TCP客户端发送数据,但TCP服务器接收空数据,android,sockets,tcp,server,client,Android,Sockets,Tcp,Server,Client,我的应用程序中有一个TCP客户端和一个TCP服务器类。 客户端发送小字符串,如“1 | 2 |”或“1 | 11 |” 客户端类 public class TcpClient { private static final int MAX_DATA_RETRY = 1; private static final int PING_TIMEOUT = 100; private ClientThread thread; private boolean mRun = true; private P
public class TcpClient {
private static final int MAX_DATA_RETRY = 1;
private static final int PING_TIMEOUT = 100;
private ClientThread thread;
private boolean mRun = true;
private PrintWriter mBufferOut;
private String mIPAdress;
private ArrayList<BufferDataItem> messageBuffer = new ArrayList<BufferDataItem>();
private Socket mSocket;
public TcpClient()
{
thread = new ClientThread();
thread.start();
}
private class ClientThread extends Thread {
@Override
public void run() {
while(mRun)
{
if(messageBuffer.size() <= 0)
continue;
BufferDataItem currMessage = messageBuffer.get(0);
currMessage.retryCount++;
if(currMessage.retryCount > MAX_DATA_RETRY)
{
messageBuffer.remove(0);
continue;
}
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(currMessage.ip);
//Log.e("TCP Client", "C: Connecting...");
try {
if(!serverAddr.isReachable(PING_TIMEOUT))
{
//only attempt to connect to devices that are reachable
messageBuffer.remove(0);
continue;
}
//create a socket to make the connection with the server
mSocket = new Socket(serverAddr, TcpManager.SERVER_PORT);
//Log.i("TCP Debug", "inside try catch");
//sends the message to the server
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true);
String message = currMessage.message;
if (mBufferOut != null && !mBufferOut.checkError()) {
Log.d("TCP SEND", "PUTTING IN BUFFER! " + message);
mBufferOut.println(message);
listener.messageSent(message, currMessage.ip);
messageBuffer.remove(0);
}
mBufferOut.flush();
}
catch (ConnectException e) {
//Connection refused by found device!
//Log.e("TCP", "C: ConnectException ip = "+currMessage.ip, e);
listener.hostUnreachable(currMessage.ip);
continue;
}
catch (Exception e) {
Log.e("TCP", "S: Error", e);
listener.messageSendError(e);
}
finally {
if(mSocket != null)
mSocket.close();
}
}
catch (Exception e) {
Log.e("TCP", "C: Error", e);
listener.messageSendError(e);
continue;
}
}
}
}
/**
* Sends the message entered by client to the server
*
* @param message text entered by client
*/
public void sendMessage(String message) {
BufferDataItem data = new BufferDataItem();
data.message = message;
data.ip = mIPAdress;
messageBuffer.add(data);
}
public void sendMessage(String message, String ip) {
mIPAdress = ip;
BufferDataItem data = new BufferDataItem();
data.message = message;
data.ip = mIPAdress;
messageBuffer.add(data);
}
/**
* Close the connection and release the members
*/
public void stopClient() {
Log.i("Debug", "stopClient");
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mBufferOut = null;
}
private class BufferDataItem
{
public String message = "";
public int retryCount = 0;
public String ip = "";
}
private OnMessageSent listener = null;
public interface OnMessageSent {
public void messageSent(String message, String ip);
public void hostUnreachable(String ip);
public void messageSendError(Exception e);
}
public void setMessageSentListener(OnMessageSent listener)
{
this.listener = listener;
}
public void removeMessageSentListener()
{
this.listener = null;
}
}
这在最初几次运行时工作正常,然后客户端发送“1 | 11 |”,服务器在读取期间将st设置为null。
字符串st=input.readLine()
有人有什么建议吗?我认为服务器在一段时间后没有收到有效数据有两个可能的原因
s
,因为mEnd
从未设置为true。客户端为每条消息打开一个新的TCP连接。服务器为连接创建套接字,但它从不关闭套接字,连接的服务器端保持打开状态。这是一个资源泄漏,可能会导致问题ArrayList messageBuffer
ArrayList
不是线程安全的集合,并且从多个线程使用了messageBuffer
。在此处使用synchronizedList
是安全的。看到手术室了吗我发现服务器在一段时间后没有收到有效数据的两个可能原因
s
,因为mEnd
从未设置为true。客户端为每条消息打开一个新的TCP连接。服务器为连接创建套接字,但它从不关闭套接字,连接的服务器端保持打开状态。这是一个资源泄漏,可能会导致问题ArrayList messageBuffer
ArrayList
不是线程安全的集合,并且从多个线程使用了messageBuffer
。在此处使用synchronizedList
是安全的。看到手术室了吗ArrayList不是线程安全的容器。客户端代码修改来自不同线程的
messageBuffer
,而不进行任何同步。此外,mEnd
在服务器代码中从未设置为true。所以服务器永远不会关闭客户端套接字和相关流->资源泄漏。感谢Zaboj。我必须承认,多线程确实让我头疼。你能推荐一个线程安全的替代ArrayList吗?对于服务器,我认为套接字必须保持打开状态,以便继续接收正在进行的数据。不是这样吗?客户端为每条消息创建一个新的tcp连接。服务器为每个tcp连接创建一个新套接字。这些插座必须关闭。也许这不是主要的错误,但服务器在长时间运行后将缺少资源。谢谢。ArrayList的线程安全替代品呢?ArrayList不是线程安全的容器。客户端代码修改来自不同线程的messageBuffer
,而不进行任何同步。此外,mEnd
在服务器代码中从未设置为true。所以服务器永远不会关闭客户端套接字和相关流->资源泄漏。感谢Zaboj。我必须承认,多线程确实让我头疼。你能推荐一个线程安全的替代ArrayList吗?对于服务器,我认为套接字必须保持打开状态,以便继续接收正在进行的数据。不是这样吗?客户端为每条消息创建一个新的tcp连接。服务器为每个tcp连接创建一个新套接字。这些插座必须关闭。也许这不是主要的错误,但服务器在长时间运行后将缺少资源。谢谢。作为ArrayList的线程安全替代方案呢?
public class TcpServer {
private ServerThread thread;
private boolean mRun = true;
private boolean mEnd = false;
public TcpServer()
{
thread = new ServerThread();
thread.start();
}
private class ServerThread extends Thread {
@Override
public void run() {
try {
Boolean end = false;
ServerSocket ss = new ServerSocket(TcpManager.SERVER_PORT);
while (mRun) {
//Server is waiting for client here, if needed
Socket s = ss.accept();
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
//PrintWriter output = new PrintWriter(s.getOutputStream(), true); //Autoflush
String st = input.readLine();
String remoteIP = s.getRemoteSocketAddress().toString();
int index = remoteIP.indexOf(":");
remoteIP = remoteIP.substring(1,index);
Log.d("TCP READ", "TCP READ: " + st);
if(st != null)
listener.messageReceived(st, remoteIP);
//output.println("Good bye and thanks for all the fish :)");
if(mEnd)
{
s.close();
mRun = false;
}
}
ss.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//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, String ip);
}
private OnMessageReceived listener = null;
public void SetMessageReceivedListener(OnMessageReceived listener)
{
this.listener = listener;
}
public void RemoveMessageReceivedListener()
{
this.listener = null;
}