これがすべてのコードです - 問題なく動作するようです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 ;
}
怒りの負荷を得る前に、アーキテクチャのいくつかの欠陥に気付きました。簡単に理解できるようにシンプルにしました (これが、読み取り/書き込みをストリームにラップしなかった理由です)。読み取りにもタイムアウトを設定しませんでしたが、それを追加するのは面倒です。
他のソースから借用したコードは、ソースに示されています。
- 作業タイマー - tick イベント内からデフォルトの android CountdownTimer をキャンセルする際に問題があるため使用されます。IP4Addess のコードは Android(TM) Application Development Cookbook から引用しました」、Wei-Meng Lee 著 p. 212 (ちなみに素晴らしい本)
(2 つ以上の f* * * リンクを投稿するのに十分な担当者がいないため、後者のコードへの URL リンクを入れることができません)
説明のために、データ ストリームへの書き込みと応答の取得の間に大幅な遅延がある場合の着信データの処理方法を次に示します。これは、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 とハンドラーを使用してそれを行うこともできましたが、これはほとんどどこでも使用できる単純なドロップイン モジュールであり、ほとんど変更する必要はありません。サービスに変換するのもかなり簡単です。
そして、関連性がなかったり、冗長だったり、自分の質問に答えたりしたことで非難される前に、その仕事を分かち合いたいと思いました。
最後に、これを試すための小さなテスト ハーネスを次に示します。
PINPad.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);
}
}
}
}