这是所有代码 - 似乎可以正常工作socketserver.zip
这是业务端:
package com.retailsci.socketserver;
/**
* Created with IntelliJ IDEA.
* User: paul
* Date: 2013/08/12
* Time: 9:06 PM
* To change this template use File | Settings | File Templates.
*/
import java.lang.ref.WeakReference;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.lang.InterruptedException;
import java.util.Enumeration;
import android.os.AsyncTask;
import java.io.BufferedInputStream ;
import java.io.BufferedOutputStream ;
import java.io.OutputStreamWriter ;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle ;
import android.os.IBinder ;
import android.os.RemoteException ;
import android.view.View ;
import android.view.View.OnClickListener ;
import android.widget.Button ;
import android.widget.Toast ;
import android.widget.TextView ;
import android.util.Log ;
import android.os.Handler;
import org.apache.http.conn.util.InetAddressUtils;
public class ServerThread implements Runnable
{
public static final String TAG = "RetailScience::ServerThread" ;
public static final int READ_OPERATION = 1 ;
public static final int WRITE_OPERATION = 2 ;
public static final int READLENGTH_OPERATION = 3 ;
public static final int WRITELENGTH_OPERATION = 4 ;
int ServerPort ;
ServerSocket serverSocket ;
Socket client ;
boolean Connected ;
String IPAddress ;
CircularByteBuffer InDataBuffer ;
CircularByteBuffer OutDataBuffer ;
public ServerThread (int ServerPort)
{
Log.v(TAG, "constructor - start") ;
this.ServerPort = ServerPort ;
IPAddress = IPv4Address() ;
Log.v(TAG, "constructor - end") ;
}
public boolean isConnected ()
{
return(Connected) ;
}
public String getIPAddress ()
{
return (IPAddress) ;
}
public void closeAll ()
{
Connected = false ; /* set the connection state */
Log.v(TAG, "Closing all the sessions");
try
{
client.close () ;
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "Socket Thread - Exception on Client Close " + e.toString());
}
try
{
serverSocket.close () ;
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "Socket Thread - Exception on serverSocket Close " + e.toString());
}
serverSocket = null ;
client = null ;
InDataBuffer = null ;
OutDataBuffer = null ;
System.gc() ;
/* Make sure the other threads can have a go now */
Thread.yield () ;
}
public boolean write (byte [] data, int offset, int length)
{
boolean okay = false ;
if (isConnected ())
{
try
{
OutDataBuffer.getOutputStream().write (data, offset, length) ;
okay = true ;
Thread.yield() ; /* Give the background thread a chance */
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "UI Thread - Probably a Connection Exception " + e.toString());
}
}
return (okay) ;
}
public void flush () /* Clear out anything in the IC buffers */
{
if (isConnected ())
{
try
{
int BytesReady = 0 ;
do
{
Thread.yield() ; /* Give the background thread a chance */
BytesReady = InDataBuffer.getInputStream().available () ;
Log.v(TAG, "FLUSH bytes" + BytesReady) ;
if (BytesReady > 0)
{
byte[] junk = new byte [BytesReady] ;
InDataBuffer.getInputStream().read (junk, 0, BytesReady) ;
}
Thread.sleep (50) ; /* Give the other thread time to pull */
/* anything else out of the IC buffer */
}
while (BytesReady > 0);
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "UI Thread - Probably a Connection Exception " + e.toString());
}
}
}
public int available ()
{
int BytesReady = -1 ;
if (isConnected ())
{
try
{
BytesReady = InDataBuffer.getInputStream().available () ;
if (BytesReady > 0)
{
Log.v(TAG, "Bytes in incoming buffer " + BytesReady) ;
}
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "UI Thread - Probably a Connection Exception " + e.toString());
}
}
return (BytesReady) ;
}
public int read (byte [] data, int offset, int length) throws IOException
{
int BytesRead = -1 ;
if (isConnected ())
{
Log.v(TAG, "********* reading data " + length) ;
try
{
BytesRead = 0 ;
int totalBytesRcvd = 0 ; // Total bytes received so far
while (totalBytesRcvd < length)
{
if ((BytesRead =
InDataBuffer.getInputStream().read (data,
totalBytesRcvd + offset,
length - totalBytesRcvd)) == -1)
{
Log.e(TAG, "UI Thread Connection Exception in Read");
throw new SocketException("Connection closed prematurely");
}
Log.v(TAG, "********* bytes read " + BytesRead) ;
totalBytesRcvd += BytesRead ;
Log.v(TAG, "********* total bytes read " + totalBytesRcvd) ;
}
BytesRead = length ;
}
catch (Exception e)
{
final String error = e.getLocalizedMessage();
Log.e(TAG, "UI Thread - Probably a Connection Exception " + e.toString());
}
}
return (BytesRead) ;
}
//---get the local IPv4 address---
// Taken from "Android(TM) Application Development Cookbook", by Wei-Meng Lee
// p. 212
// (Very useful book by the way)
private String IPv4Address()
{
try {
for (Enumeration<NetworkInterface> networkInterfaceEnum = NetworkInterface
.getNetworkInterfaces(); networkInterfaceEnum
.hasMoreElements();)
{
NetworkInterface networkInterface = networkInterfaceEnum.nextElement();
for (Enumeration<InetAddress> ipAddressEnum
= networkInterface.getInetAddresses(); ipAddressEnum.hasMoreElements();)
{
InetAddress inetAddress = (InetAddress) ipAddressEnum.nextElement();
// ---check that it is not a loopback address and
// it is IPv4---
if (!inetAddress.isLoopbackAddress()
&&
InetAddressUtils.isIPv4Address(inetAddress.getHostAddress()))
{
return inetAddress.getHostAddress();
}
}
}
}
catch (SocketException e)
{
Log.e(TAG, "IPv4Address " + e.toString());
}
return null;
}
public void run ()
{
try
{
if (IPAddress != null)
{
Log.v(TAG, "Starting...");
// handler.post(new Runnable()
// {
// @Override
// public void run()
// {
// textView1.setText(textView1.getText()
// + "Server listening on IP: " + SERVER_IP
// + "\n");
// }
// });
//---create an instance of the server socket---
//--- Allow 2 outstanding connections
serverSocket = new ServerSocket(ServerPort, 1);
/* allow the socket to be reused - or we'll get INUSE exception*/
serverSocket.setReuseAddress(true) ;
int Counter = 0 ;
Log.v(TAG, "Server Thread Running");
while (true)
{
//---wait for incoming clients---
Socket client = serverSocket.accept();
Log.v(TAG, "Connection Detected");
Connected = true ; /* set the connection state */
//---the above code is a blocking call;
// i.e. it will block until a client connects---
try
{
InDataBuffer = new CircularByteBuffer() ;
OutDataBuffer = new CircularByteBuffer() ;
BufferedInputStream InStream = new BufferedInputStream (client.getInputStream()) ;
BufferedOutputStream OutStream = new BufferedOutputStream (client.getOutputStream()) ;
int BytesDataBuffer ;
while (true)
{
if (Counter >= 1500) /* About 15 seconds */
{
/* Done' print this out too often */
Counter = 0 ;
Log.v(TAG, "Server Thread Running");
}
++Counter ;
BytesDataBuffer = InStream.available() ;
if (BytesDataBuffer > 0)
{
Log.v(TAG, "Reading Data Bytes " + BytesDataBuffer);
byte [] TempBuffer = new byte [BytesDataBuffer] ;
InStream.read (TempBuffer, 0, BytesDataBuffer) ;
InDataBuffer.getOutputStream().write (TempBuffer, 0, BytesDataBuffer);
Log.v(TAG, "Read Data Bytes " + BytesDataBuffer);
}
BytesDataBuffer = OutDataBuffer.getInputStream().available() ;
if (BytesDataBuffer > 0)
{
Log.v(TAG, "Writing Data Bytes " + BytesDataBuffer);
byte [] TempBuffer = new byte [BytesDataBuffer] ;
OutDataBuffer.getInputStream().read (TempBuffer, 0, BytesDataBuffer) ;
OutStream.write (TempBuffer, 0, BytesDataBuffer);
OutStream.flush() ; /* Make sure the buffer is empty */
Log.v(TAG, "Wrote Data Bytes " + BytesDataBuffer);
}
Thread.sleep(100) ; /* Always yield for a bit */
}
}
catch (Exception e)
{
Log.e(TAG, "Socket Thread - Read Exception " + e.toString());
Connected = false ; /* set the connection state */
}
} /* while (true) */
}
else
{
Log.e(TAG, "Socket Thread - No Network Capability");
Connected = false ; /* set the connection state */
}
}
catch (Exception e)
{
Log.e(TAG, "Socket Thread - Probably a Connection Exception" + e.toString());
Connected = false ; /* set the connection state */
}
closeAll () ;
Log.v(TAG, "*********************************************** Socket Thread - Connection Terminated");
Log.v(TAG, "*********************************************** Socket Thread - Connection Terminated");
Log.v(TAG, "*********************************************** Socket Thread - Connection Terminated");
Log.v(TAG, "*********************************************** Socket Thread - Connection Terminated");
}
}
读取和写入的示例位于:DeviceIF.java(在 zip 文件中)但是,这里有一些主要的原语:
ServerThread SocketIF ;
Thread BackgroundThread ;
To start it
SocketIF = new ServerThread (12347) ; /* 12347 is the server I/C port */
BackgroundThread = new Thread(SocketIF);
BackgroundThread.setDaemon(true) ; /* Make this a Daemon Thread */
BackgroundThread.start();
To stop it
SocketIF.closeAll () ;
Thread.yield () ; /* give the thread time to find out it's dead */
if (BackgroundThread != null)
{
if (BackgroundThread.isAlive())
{
BackgroundThread.interrupt (); /* Get rid of the thread */
Thread.yield () ; /* give the thread time to find out it's dead */
}
}
To read
try
{
if (SocketIF.isConnected ())
{
byte [] ResponseBuffer = new byte [7] ;
int Result = SocketIF.read (ResponseBuffer, 0, 7) ;
}
}
catch (Exception e)
{
final String error = e.getLocalizedMessage() ;
Log.e(TAG, "Exception : " + error);
}
To Write
int Result = ERROR_FAILED ;
try
{
if (SocketIF.isConnected ()) /* see if it's still open */
{
// flushICData () ; Good idea to do this before you issue a request
int RequestLen = 0 ;
final byte [] RequestBuffer = new byte [20] ;
RequestBuffer [RequestLen++] = (byte) 0 ; /* This will eventually hold the length */
RequestBuffer [RequestLen++] = (byte) '1' ;
RequestBuffer [0] = (byte) ((RequestLen - 1) & 0xFF) ; /* Put in the length one byte's enough */
SocketIF.write (RequestBuffer, 0, RequestLen) ;
Result = ERROR_OKAY ;
}
else
{
Result = ERROR_NO_CONNECTION ;
}
}
catch (Exception e)
{
final String error = e.getLocalizedMessage() ;
Log.e(TAG, "Exception : " + error);
Result = ERROR_EXCEPTION ;
}
在我获得大量仇恨之前,我已经意识到架构中的一些缺陷;我保持简单以使其更易于理解(这就是我没有将读/写内容包装在流中的原因)。我也没有在读取中设置超时,但这将是一个轻而易举的补充。
我从其他来源借来的代码在来源中注明:
- 工作计时器 - 使用是因为从滴答事件中取消默认的 android CountdownTimer 时出现问题 循环缓冲区 - 用于提供一个很好的简单循环缓冲区流以允许从服务器进行异步读取和写入。IP4Addess 代码来自 Android(TM) Application Development Cookbook”,作者 Wei-Meng Lee,第 212 页(顺便说一句很棒的书)
(我无法将 URL 链接放入后面的代码,因为我没有足够的代表来发布两个以上的 f* * * 链接)
出于说明的目的,如果在写入数据流和获得响应之间存在显着延迟,以下是处理传入数据的方法。这是从 Countdowntimer 中的 onTick 事件调用的(在我的情况下是 Workingtimer,因为上面提到的定时器取消问题)
protected void TickHandler ()
{
try
{
/* See if we have connected yet */
if (TerminalIF.isConnected ())
{
/* See if we have connected yet */
Button btn ;
btn = (Button) findViewById (R.id.getpinbutton);
btn.setEnabled(true) ;
btn = (Button) findViewById (R.id.displaybutton);
btn.setEnabled(true) ;
btn = (Button) findViewById (R.id.getcardstatebutton);
btn.setEnabled(true) ;
btn = (Button) findViewById (R.id.rebootbutton);
btn.setEnabled(true) ;
btn = (Button) findViewById (R.id.pingbutton);
btn.setEnabled(true) ;
if (TerminalIF.responseReady ())
{
byte [] DataResult = TerminalIF.ReceivePacket () ;
Log.v(TAG, "Data Received") ;
Toast.makeText(getApplicationContext(),
"Device Data Received",
Toast.LENGTH_SHORT).show() ;
resetTimer (DEFAULT_INPUT_TIMER_TIMEOUT) ;
}
}
}
catch (Exception e)
{
final String error = e.getLocalizedMessage() ;
Log.e(TAG, "Exception : " + error);
}
}
是的,我可以使用 AsyncTasks 和处理程序来完成它,但这是一个直接的插件模块,几乎可以在任何地方使用,几乎不需要修改。转换成服务也很容易。
而且,在我因无关紧要、冗长或回答我自己的问题而被指责之前,我只是想我会分享这项工作。
最后一件事,这里有一个小测试工具可以试用:
密码键盘.java
import java.io.*;
import java.net.*;
import java.lang.* ;
public class PINPad
{
InputStream in ;
OutputStream out ;
byte [] receive (int len) throws IOException
{
byte [] result = null ;
if (len > 0)
{
byte [] temp = new byte [len] ;
// Receive the same string back from the server
int totalBytesRcvd = 0; // Total bytes received so far
int bytesRcvd ; // Bytes received in last read
while (totalBytesRcvd < temp.length)
{
if ((bytesRcvd = in.read(temp, totalBytesRcvd, temp.length - totalBytesRcvd)) == -1)
{
System.out.println("Error on receive");
throw new SocketException("Connection closed prematurely");
}
else
{
System.out.println("Received " + bytesRcvd + " bytes");
}
totalBytesRcvd += bytesRcvd;
} // data array is full
result = temp ;
}
return result ;
}
void send (byte [] data, int offset, int len) throws IOException
{
System.out.println("Sending.... " + len + " bytes");
if (len > 0)
{
try
{
out.write (data, offset, len) ;
}
catch (Exception e)
{
System.out.println("Error on send");
throw new SocketException("Connection closed prematurely");
}
}
System.out.println("Sent " + len + " bytes");
}
void loop (Socket echoSocket)
{
boolean okay = true ;
try
{
in = echoSocket.getInputStream();
out = echoSocket.getOutputStream();
}
catch (Exception e)
{
okay = false ;
}
while (okay)
{
try
{
System.out.println("Receive length");
byte [] len = receive (1) ;
int packetlength = (int) len[0] ;
System.out.println("Subsequent packet length = " + packetlength);
byte [] packet = receive (packetlength) ;
System.out.println("Got a packet of = " + packet.length);
char packettype = (char) packet [0] ;
byte [] retbuf = new byte [50] ;
int reqlen = 0 ;
switch (packettype)
{
case 'A' : /* PING */
System.out.println("==== PING");
retbuf [reqlen++] = (byte) 0 ; /* placeholder for the length */
retbuf [reqlen++] = (byte) packettype ;
retbuf [reqlen++] = (byte) '0' ; /* Error code = OK */
retbuf [0] = (byte) (reqlen - 1) ; /* Now put the length in */
send(retbuf, 0, reqlen);
break ;
case 'B' : /* GET PIN */
System.out.println("==== GET PIN");
retbuf [reqlen++] = (byte) 0 ; /* placeholder for the length */
retbuf [reqlen++] = (byte) packettype ;
retbuf [reqlen++] = (byte) '0' ; /* Error code = OK */
retbuf [0] = (byte) (reqlen - 1) ; /* Now put the length in */
send(retbuf, 0, reqlen);
break ;
case 'C' : /* GET CARD STATE */
System.out.println("==== GET CARD STATE");
retbuf [reqlen++] = (byte) 0 ; /* placeholder for the length */
retbuf [reqlen++] = (byte) packettype ;
retbuf [reqlen++] = (byte) '0' ; /* Error code = OK */
retbuf [reqlen++] = (byte) '1' ; /* Card is present */
retbuf [0] = (byte) (reqlen - 1) ; /* Now put the length in */
send(retbuf, 0, reqlen);
break ;
case 'D' : /* DISPLAY */
System.out.println("==== DISPLAY");
retbuf [reqlen++] = (byte) 0 ; /* placeholder for the length */
retbuf [reqlen++] = (byte) packettype ;
retbuf [reqlen++] = (byte) '0' ; /* Error code = OK */
retbuf [0] = (byte) (reqlen - 1) ; /* Now put the length in */
send(retbuf, 0, reqlen);
break ;
case 'E' : /* REBOOT */
System.out.println("==== REBOOT");
okay = false ;
break ;
case 'F' : /* CLOSE */
System.out.println("==== CLOSE SESSION");
okay = false ;
break ;
default :
System.out.println("==== UNKNOWN!!!!!!");
retbuf [reqlen++] = (byte) 0 ; /* placeholder for the length */
retbuf [reqlen++] = (byte) packettype ;
retbuf [reqlen++] = (byte) '3' ; /* error */
retbuf [0] = (byte) (reqlen - 1) ; /* Now put the length in */
send(retbuf, 0, reqlen);
break ;
}
}
catch (Exception e)
{
okay = false ;
}
}
try
{
out.close();
in.close();
}
catch (Exception e)
{
okay = false ;
}
}
public static void main(String[] args)
{
Socket echoSocket = null;
PINPad IF = new PINPad () ;
while (true)
{
try
{
echoSocket = new Socket("192.168.168.106", 12347);
// out = new PrintWriter(echoSocket.getOutputStream(), true);
// in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
if (echoSocket != null)
{
System.out.println("Connected to remote");
IF.loop (echoSocket) ;
echoSocket.close();
System.out.println("Waiting for next connection");
}
}
catch (UnknownHostException e)
{
System.err.println("Don't know about host: 192.168.168.107.");
// System.exit(1);
}
catch (IOException e)
{
System.err.println("Couldn't get I/O for the connection to: 192.168.168.107.");
}
catch (Exception e)
{
System.err.println("Couldn't get I/O for the connection to: 192.168.168.107.");
}
try
{
Thread.sleep (1000) ;
}
catch (Exception e)
{
System.err.println("Thread Interrupted....");
System.exit(1);
}
}
}
}