I created a server thread(using sockets). I recently got a new requirement that I need to add message to the user to notify him when there is a problem with the communication, I added a counter that counts how many exception I have during the communication lose and if it's equal to SERVER_MAX_NUM_TRIES I need to show to the user the message.
I tried many things but it does not work as it is suppose to.
This is my code so far:
public ServerNetworkThread()
{
setName("ServerNetworkThread");
_port = 5555;
_excetionCounter = 0;
}
#Override
public void run()
{
_isWorking = true;
while(_isWorking)
{
try
{
_serverSocket = new ServerSocket();
_serverSocket.setReuseAddress(true);
_serverSocket.bind(new InetSocketAddress(_port));
_socket = _serverSocket.accept();
_socket.setSoTimeout(Consts.CLIENT_SOCKET_TIMEOUT);
parseCommand();
_socket.close();
_serverSocket.close();
_excetionCounter = 0;
}
catch (IOException e)
{
Log.d("anton","server got exception _excetionCounter="+_excetionCounter);
e.printStackTrace();
_excetionCounter++;
if(_excetionCounter == SERVER_MAX_NUM_TRIES)
{
_isWorking = false;
Logics.getInstance().getNetworkManager().sendCommand(_handler, Consts.Requests.CONNECTION_SERVER_ERROR_MESSAGE, null);
}
}
}
}
private void parseCommand() throws IOException
{
InputStream iStream = _socket.getInputStream();
InputStreamReader in = new InputStreamReader(iStream, Charset.forName("UTF-16LE"));
DataOutputStream outToClient = new DataOutputStream(_socket.getOutputStream());
char[] buf = new char[1024];
int lettersCount = in.read(buf, 0, buf.length);
String request = new String(buf,0,lettersCount);
String responseStr = parseResponse(request);
byte[] response = responseStr.getBytes("UTF-16LE");
outToClient.write(response);
outToClient.flush();
outToClient.close();
in.close();
}
}
When I simulate a communication problem unplug the Ethernet cable nothing is happening.
UPDATE:
without using the second inner loop I'm getting this exception
java.net.BindException: bind failed: EADDRINUSE (Address already in use)
Related
I have a simple SSDP search, but sometimes I get a Address in Use error
public void search(String service, CallbackContext callbackContext) throws IOException {
final int SSDP_PORT = 1900;
final int SSDP_SEARCH_PORT = 1901;
final String SSDP_IP = "239.255.255.250";
int TIMEOUT = 3000;
InetSocketAddress srcAddress = new InetSocketAddress(SSDP_SEARCH_PORT);
InetSocketAddress dstAddress = new InetSocketAddress(InetAddress.getByName(SSDP_IP), SSDP_PORT);
// Clear the cached Device List every time a new search is called
mDeviceList = new JSONArray();
// M-Search Packet
StringBuffer discoveryMessage = new StringBuffer();
discoveryMessage.append("M-SEARCH * HTTP/1.1\r\n");
discoveryMessage.append("HOST: " + SSDP_IP + ":" + SSDP_PORT + "\r\n");
discoveryMessage.append("ST:"+service+"\r\n");
//discoveryMessage.append("ST:ssdp:all\r\n");
discoveryMessage.append("MAN: \"ssdp:discover\"\r\n");
discoveryMessage.append("MX: 2\r\n");
discoveryMessage.append("\r\n");
System.out.println("Request: " + discoveryMessage.toString() + "\n");
byte[] discoveryMessageBytes = discoveryMessage.toString().getBytes();
DatagramPacket discoveryPacket = new DatagramPacket(discoveryMessageBytes, discoveryMessageBytes.length, dstAddress);
// Send multi-cast packet
MulticastSocket multicast = null;
try {
multicast = new MulticastSocket(null);
multicast.bind(srcAddress);
multicast.setTimeToLive(4);
multicast.send(discoveryPacket);
} finally {
multicast.disconnect();
multicast.close();
}
// Create a socket and wait for the response
DatagramSocket wildSocket = null;
DatagramPacket receivePacket;
try {
wildSocket = new DatagramSocket(SSDP_SEARCH_PORT);
wildSocket.setSoTimeout(TIMEOUT);
while (true) {
try {
receivePacket = new DatagramPacket(new byte[1536], 1536);
wildSocket.receive(receivePacket);
String message = new String(receivePacket.getData());
try {
JSONObject device = new JSONObject();
device.put("USN", parseHeaderValue(message, "USN"));
device.put("LOCATION", parseHeaderValue(message, "LOCATION"));
device.put("ST", parseHeaderValue(message, "ST"));
device.put("Server", parseHeaderValue(message, "Server"));
createServiceObjWithXMLData(parseHeaderValue(message, "LOCATION"), device);
} catch (JSONException e) {
e.printStackTrace();
}
} catch (SocketTimeoutException e) {
callbackContext.success(mDeviceList);
break;
}
}
} finally {
if (wildSocket != null) {
wildSocket.disconnect();
wildSocket.close();
}
}
}
How can I set it to a dynamic port, instead of 1901?
I tried doing multicast.setReuseAddress(true); but it still gives the same error
I looked at this SO, it suggests the same thing but in my case it doesn't work as expected. I keep getting the same error.
How can I fix this issue?
This line:
multicast = new MulticastSocket(null);
should change to:
multicast = new MulticastSocket();
multicast.setReuseAddress(true);
multicast.bind(srcAddress);
This will depend on platform. If getReuseAddress() return false, your device does not support. https://developer.android.com/reference/java/net/DatagramSocket.html#setReuseAddress(boolean)
Note: This functionality is not supported by all existing platforms, so it is implementation specific whether this option will be ignored or not. However, if it is not supported then getReuseAddress() will always return false.
I'm having an issue with a messaging app I'm working on and was hoping someone could point me in the right direction. I'm stuck on getting the client and server to communicate properly.
My client multicasts a message to 5 processes, which make their alterations on the server side and send them back to the client. This all works fine, however when I try to multicast a second time, the server is getting stuck reading and eventually gives me the error: W/System.err (with no other information) at the line I point out in the code.
Client code:
private class ClientTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... msgs) {
try{
String msg = msgs[0];
int ID = Integer.parseInt(msgs[1]);
ObjectOutputStream out;
clock++;
Message m1 = new Message(clock, msg, ID);
for (int i = 0; i < 5; ++i) {
String remotePort = REMOTE_PORT[i];
Socket socket = new Socket(InetAddress.getByAddress(new byte[]{10, 0, 2, 2}),
Integer.parseInt(remotePort));
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(m1);
out.flush();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Message m2 = (Message)in.readObject();
proposed_seq_from_q = m2.seq_number;
all_proposed.add(proposed_seq_from_q);
socket.close();
}
agreed_deliver = Collections.max(all_proposed);
m1.set_seq_number(agreed_deliver);
for (int i = 0; i < 5; ++i) {
String remotePort = REMOTE_PORT[i];
Socket socket = new Socket(InetAddress.getByAddress(new byte[]{10, 0, 2, 2}),
Integer.parseInt(remotePort));
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(m1);
out.flush();
socket.close();
}
} catch(ClassNotFoundException e){
Log.e(TAG, "ClientTask: ClassNotFoundException");
e.printStackTrace();
} catch (UnknownHostException e) {
Log.e(TAG, "ClientTask: UnknownHostException");
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "ClientTask: IOException");
e.printStackTrace();
}
return null;
}
}
Server code:
private class ServerTask extends AsyncTask<ServerSocket, String, Void> {
#Override
protected Void doInBackground(ServerSocket... sockets) {
ServerSocket serverSocket = sockets[0];
boolean listening = true;
try{
while(listening) {
Socket clientSocket = serverSocket.accept();
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
Message m = (Message)in.readObject();
new_proposed = Math.max(new_proposed + 1, clock);
m.set_seq_number(new_proposed);
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
out.writeObject(m);
holdback_queue.add(m);
// ******************************************************
// THIS IS WHERE IT IS CRASHING
// ******************************************************
m = (Message)in.readObject();
publishProgress(m.get_message());
}
}catch(Exception e){
Log.e(TAG, "FAIL");
e.printStackTrace();
}
return null;
}
I've tried everything I can think of but I'm unable to get the server to read the second message. Everything is working up and being passed through with no issues up until that exact point. Can anyone please tell me what I'm doing wrong?
So I have this really, really strange problem with getting data using socket from server which is working on my PC to Android app. All in local network for now.
It is strange, because I wrote server and client apps (both using sockets) to send and get data and it works really great. I tried to do exactly the same on Android and it gets only first response from server, but not the rest after sending token.
I searched through SO and saw piece of advice that available() method is not right so I changed it and it's still not working as I wish it would.
I think there is something wrong with server-side app or android app works way too fast for server and it sends data after ending transmission on android, but I tried to give it a bit of time and nothing...
This is server app (in general it gets token, lets say "RAM" then it gets output from linux process and sends it straight to android app):
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
public class BLCServer extends Thread{
private ServerSocket serverSocket;
public BLCServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(86400000);
}
public void run() {
while(true) {
try {
String token = "";
System.out.println("Waiting for a client on port: "+serverSocket.getLocalPort());
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
System.out.println("Beginning transmission");
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("Thanks for connecting to " + server.getLocalSocketAddress() + "Goodbye\n");
while(token != "END") {
token = in.readUTF();
if(token.equals("RAM")) {
Ram ram = new Ram();
List<String> ramData = new ArrayList<>();
ramData = ram.getRamData();
System.out.println("RAM");
System.out.println("ram.size(): " + ramData.size());
out.writeUTF("ramBeginning");
for(String x : ramData) {
System.out.println("Wysyłam do clienta: " + x);
out.writeUTF(""+x);
}
out.writeUTF("ramEnd");
} else if(token.equals("CPU")) {
Cpu cpu = new Cpu();
List<String> cpuData = new ArrayList<>();
cpuData = cpu.getCpuLoad();
System.out.println("CPU");
out.writeUTF("cpuBeginning");
for(String x : cpuData) {
out.writeUTF(x);
}
out.writeUTF("cpuEnd");
} else if(token.equals("STORAGE")) {
Storage storage = new Storage();
List<String> storageData = new ArrayList<>();
storageData = storage.printStorageData();
System.out.println("STORAGE");
out.writeUTF("storageBeginning");
for(String x : storageData) {
out.writeUTF(x);
}
out.writeUTF("storageEnd");
} else if(token.equals("UPTIME")) {
Uptime uptime = new Uptime();
String uptimeData = uptime.getUptime();
System.out.println("UPTIME");
out.writeUTF("uptimeBeginning");
out.writeUTF(uptimeData);
out.writeUTF("uptimeEnd");
} else if(token.equals("TEMPERATURES")) {
out.writeUTF("temperaturesBeginning");
out.writeUTF("temperaturesEnd");
} else if(token.equals("END")) {
break;
} else {
out.writeUTF("Token unknown");
}
}
server.close();
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
int port = 1984;
try {
Thread t = new BLCServer(port);
t.start();
} catch(IOException e) {
e.printStackTrace();
}
}
}
And also there is android main activity:
public class MyActivity extends Activity {
TextView cpuT;
TextView ramT;
TextView uptimeT;
TextView storageT;
List<String> ram = new ArrayList<String>();
List<String> cpu = new ArrayList<String>();
List<String> uptime = new ArrayList<String>();
List<String> storage = new ArrayList<String>();
List<String> temperatures = new ArrayList<String>();
public class NetThread extends AsyncTask<String, Void, Void> {
String dstAddress = "192.168.0.111";
int dstPort = 1984;
#Override
protected Void doInBackground(String... args) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
OutputStream outToServer = socket.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
InputStream inFromServer = new PushbackInputStream(socket.getInputStream());
DataInputStream in = new DataInputStream(inFromServer);
out.writeUTF("Hello from " + socket.getLocalSocketAddress());
int singleByte;
ramT.setText(in.readUTF());
out.writeUTF("RAM");
while((singleByte = inFromServer.read()) != -1) { // there was code like: while(in.available() > 0) { ... } but someone wrote about it's bad behaviour on SO
ramT.setText(ramT.getText() + "\n" + singleByte);
}
}
out.writeUTF("END");
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("WEBSERVICE", "Oncreate wywołane\n");
cpuT = (TextView) findViewById(R.id.displayCpu);
ramT = (TextView) findViewById(R.id.displayRam);
uptimeT = (TextView) findViewById(R.id.displayUptime);
storageT = (TextView) findViewById(R.id.displayStorage);
NetThread netThread = new NetThread();
netThread.execute("RAM", "STORAGE", "UPTIME");
}
}
In addition I paste you client application for pc:
public class BLCClient {
public static void main(String[] args) {
String serverName = "localhost";
int port = 1984;
try {
System.out.println("Connecting to..."+serverName+" on port 1984");
Socket client = new Socket(serverName, port);
System.out.println("Just connected to "+client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
Scanner cin = new Scanner(System.in);
String token = "";
out.writeUTF("Hello from " + client.getLocalSocketAddress());
System.out.println("Server says: "+in.readUTF());
while(true) {
System.out.println("Podaj token ciulu: ");
token = cin.nextLine();
System.out.println("Twój token: " + token);
if(token.equals("END")) {
out.writeUTF(token);
break;
} else {
out.writeUTF(token);
System.out.println(in.readUTF());
System.out.println("IN: " + in.available());
while(in.available() > 0) {
System.out.println(in.readUTF());
}
}
}
client.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
Yes. I'm using part of code from tutorialspoint.com. If you need classes for getting data for ram, cpu, storage, temperatures or uptime processes let me know.
For now I've spent around 4 days trying to figure out what is wrong with my code for android (because servers sends data correctly, I'm 99% sure). Please help me. I'm powerless and I want this app wake to work so so badly right now (Actually I made this work using tomcat server, but I want my own server in here).
Thanks.
I need some advice and help troubleshooting a client/server interaction for a cellular modem project I'm working on. The client and server are written in Java.
The questions I need some advice on are as follows:
(1) I'm seeking advice on whether the approach I'm taking is going to scale up for large files (Code to follow) especially in the context of a cellular network where the network can drop out unexpectedly. Large files being ~1GB. The large file represent an image that is transferred from the server to client. This represents the worst case scenario. The base case contains files that are relatively small, containing GPS Data and Time Stamp info. These files are likely in the KB to a couple of MB range and transferred often.
(2) Need advice on troubleshooting the client/server code. Even if this approach isn't going to work for larger files, I would like to get the code working for the base case to support a proof of concept test in the near future. Software updates are not required for the proof of concept.
Background on the client/server interaction. The client contacting the server. The server detects the client request which starts a new thread to handle the client. The client transmits a serilaize Data Packet. The Data Packet contains some header info (file size, crc, file type) and a data payload. Upon receiving the data packet object, the server verifies the crc and file size match the values include in the header. The server responds with a data packet object which indicates whether the transmission was valid or not. If the client receives a valid response from the server the client sends a good bye packet to close the session. If the response was invalid from the server, the client will resend the data and will eventually quit after x failed attempts. Eventually, the client will get a set of instructions from the server which can instruct it to upload a log file, download a new .jre file, or even a new firmware image.
Here is the error that I'm getting on the server code:
Feb 16, 2013 7:36:40 AM noaa.logbook.server.ServerConnectionHandler run
SEVERE: null
java.io.EOFException
at
java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2553)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1296)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at noaa.logbook.server.ServerConnectionHandler.run(ServerConnectionHandler.java:69)
at java.lang.Thread.run(Thread.java:662)
The data arrives as the server and it looks exception occurs on the next time I tried to read an object on the objectinputstream, which is the goodbye packet.
Client Code:
public static boolean clientTransmit(Socket sockToServer, String fileName, int dataPacketType, String id, String fileTimeStamp) {
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
//TCPConnection tcpConn = null;
DataPacket packet = null;
File inputFile = new File(fileName);
boolean fileExists = inputFile.exists();
int size = 0;
int failedAttempts = 0;
String contents = null;
byte[] ref = null;
boolean success = false;
boolean bye = false;
try
{
sockToServer.setSoTimeout(5000);
if ((sockToServer.isConnected()) && (fileExists)) {
System.out.println("LogBookClientCommunications: Connected to Server");
System.out.print("Stage 0");
contents = readFile(fileName);
packet = LogBookUtilities.packageDataPacket(DataPacket.UPLOAD_DATA, contents, LogBookClient.SOFTWARE_VERSION, LogBookClient.serialNumber);
oos = new ObjectOutputStream(sockToServer.getOutputStream());
oos.writeObject(packet);
oos.flush();
System.out.println("LogBookClientCommunications: Sending DataPacket");
ois = new ObjectInputStream(sockToServer.getInputStream());
while(!success && failedAttempts < 3) {
Object object = ois.readObject();
if (object instanceof DataPacket) {
System.out.println("LogBookClientCommunications: Received a DataPacket Object");
DataPacket inPacket = (DataPacket)object;
byte[] compressedByteRef = inPacket.getDataArray();
boolean sizeValid = verifySize(compressedByteRef, inPacket.getLength());
boolean crcValid = verifyCRC(inPacket);
if ((sizeValid) && (crcValid)) {
System.out.println("LogBookClientCommunications: Size & CRC Valid");
String uncompressed = new String(uncompress(compressedByteRef));
String[] strRef = lookupResponsePairs(dataPacketType);
if (uncompressed.equals(strRef[0])) {
success = true;
System.out.println("LogBookClientCommunications: File arrived uncorrupted");
//tcpConn.disconnect();
} else if (uncompressed.equals(strRef[1])) {
success = false;
failedAttempts++;
System.out.println("LogBookClientCommunications: File arrived corrupted");
}
} else {
success = false;
failedAttempts++;
if (sizeValid)
System.out.println("LogBookClientCommunications: CRC InValid");
else
System.out.println("LogBookClientCommunications: Size InValid");
}
}//end if object instanceof
else {
System.out.println("LogBookClientCommunications: Not a DataPacket Object");
failedAttempts++;
}
}//while
//Close Connection by sending bye
System.out.println("LogBookClientCommunications: Sending Good Bye...");
DataPacket goodbye = LogBookUtilities.packageDataPacket(DataPacket.RESPONSE, quit", LogBookClient.SOFTWARE_VERSION, LogBookClient.serialNumber);
oos.writeObject(goodbye);
oos.flush();
}
else
{
System.out.println("LogBookClientCommunications: Failed to Connect or File Did Not Exist");
success = false;
}
}
catch (ClassNotFoundException ex) {
Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
oos.close();
ois.close();
sockToServer.close();
} catch (IOException ex) {
Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
}
}
return success;
}
Server connection handler code:
public void run()
{
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
int failedAttempts = 0;
boolean success = false;
boolean sendResponse = false;
Socket soc = getSocket();
Object obj = new Object();
long time = System.currentTimeMillis();
DataPacket inPacket = null;
DataPacket outPacket = null;
try {
System.out.println("Server Connection Handler: Receiving Connection From - " + soc.getRemoteSocketAddress());
soc.setSoTimeout(15000);
oos = new ObjectOutputStream(soc.getOutputStream());
oos.flush();
ois = new ObjectInputStream(soc.getInputStream());
if (ois == null | oos == null) {
System.out.println("Server Connection Handler: Successfull Opened Streams");
if (ois == null) { System.out.println("Server Connection Handler: ObjectInputStream Failed to Open");}
else {System.out.println("Server Connection Handler: ObjectOutputStream Failed to Open"); }
}
while (true) {
inPacket = (DataPacket)ois.readObject();
boolean validPacket = LogBookUtilities.isPacketValid(inPacket);
if (validPacket) {
if(inPacket.getField() == DataPacket.RESPONSE) {
byte[] ref = inPacket.getDataArray();
String data = LogBookUtilities.uncompress(ref);
if (data.equalsIgnoreCase("bye")) {
System.out.println("Server Connection Handler: Bye....");
break;
}
}
else if (inPacket.getField() == DataPacket.UPLOAD_DATA) {
System.out.println("Server Connection Handler: Writing data to file");
LogBookUtilities.processClientPacket(inPacket);
System.out.println("Server Connection Handler: File Successfully Transfered");
outPacket = LogBookUtilities.makeResponse(inPacket.getField(), true, LogBookServer.SOFTWARE_VERSION, LogBookServer.ID);
sendResponse = true;
}
}
else {
if (inPacket.getField() == DataPacket.UPLOAD_DATA) {
sendResponse = true;
outPacket = LogBookUtilities.makeResponse(inPacket.getField(), true, LogBookServer.SOFTWARE_VERSION, LogBookServer.ID);
}
}
if (sendResponse) {
oos.writeObject(outPacket);
oos.flush();
}
}//end while
}
catch (ClassNotFoundException ex) {
Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IOException ex) {
Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null, ex);
}
finally {
try {
ois.close();
oos.close();
soc.close();
}
catch (IOException ex) {
Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Server code:
public class LogBookServer
{
public static final String ID = "666666";
public static final String SOFTWARE_VERSION = "0.02";
public static final String VFILE = "vFile";
public static final String DASH = "-";
public static final String DATEXT = ".dat";
public static final int FAILED_THRESHOLD = 3;
private int port = 6767;
private String ip = "";
public int getListeningPort() {
return this.port;
}
public void setListeningPort(int port) {
this.port = port;
}
public void run()
throws Exception
{
Selector acceptSelector = SelectorProvider.provider().openSelector();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
InetAddress lh = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(lh, this.port);
ssc.socket().bind(isa);
SelectionKey acceptKey = ssc.register(acceptSelector, 16);
int keysAdded = 0;
while ((keysAdded = acceptSelector.select()) > 0)
{
Set readyKeys = acceptSelector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = (SelectionKey)i.next();
i.remove();
ServerSocketChannel nextReady = (ServerSocketChannel)sk.channel();
Socket s = nextReady.accept().socket();
handleConnection(s);
}
}
}
void handleConnection(Socket socket)
{
System.out.println("hadling connection....");
ServerConnectionHandler connectionHandler = new ServerConnectionHandler(socket);
new Thread(connectionHandler).start();
}
}
In your client you have (split to diff lines for readability):
DataPacket goodbye =
LogBookUtilities.packageDataPacket(DataPacket.RESPONSE,
"quit",
LogBookClient.SOFTWARE_VERSION,
LogBookClient.serialNumber);
Then in your server you have:
if (data.equalsIgnoreCase("bye")) {
Which one of these is not like the other? ;)
Your server reads the "goodbye" packet, but doesn't recognize it, then loops again and tries to read from a closed socket. Presto, IOException.
As for your question of "scalability" ... it's not so much that as efficiency. If you're worried about the network dropping out from under you, sending serialized objects probably isn't the way to go; there's no way to resume - a partial send has to be completely resent and if it's a gig of data as you state ... that's bad. You are better off using the write() methods of OutputStream with a reasonable buffer size. This will allow you to keep track of the data that's been sent and resume a transfer once the network comes back (this will require some logic being implemented between your client and server, obviously, so that you can figure out what the server has already received in the case of a network failure).
I've written some serverside socket handling code and I'm concerned that potentially my packets are not always making it back to the client. I am logging all my events and in my log files it says I am sending the information. But the client is also logging events and in their logs they say they do not receive anything.
My code to send the data is as follows:
public void write(Packet packet) {
String data = packet.serialize();
log("Send=[" + data + "]", "Write"); // log to file
try {
_writer.write(data);
_writer.flush();
} catch (Exception ex) {
log(ex, "write");
}
}
Each socket is created on a new thread and I create my writers and readers immediately like so (in the public run method):
// _sockt is a Java Socket object
_writer = new BufferedWriter(new OutputStreamWriter(_socket
.getOutputStream()));
_reader = new SocketReader(_socket);
SocketReader is just a wrapper class I created for listening for responses and has a public read method like so:
public String read() throws IOException, SocketTimeoutException {
_socket.setSoTimeout(_timeOut);
if(_reader == null)
_reader = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
// read from the stream
return new PacketDataInputStream(_reader).read();
}
The PacketDataInputStream wrapper class:
BufferedReader _reader = null;
public PacketDataInputStream(BufferedReader reader)
{
_reader = reader;
}
public String read() throws IOException, SocketException {
StringBuilder builder = new StringBuilder();
int c = 0;
while((c = _reader.read()) != -1)
{
char ch = (char)c;
builder.append(ch);
if(ch == PacketConstants.ETX)
break;
}
if(builder.length() > 0)
return builder.toString();
else
return null;
}
The way I'm creating the actual socket listener objects is pretty standard I think:
InetAddress address = InetAddress.getByName(IP);
server = new ServerSocket( port, 0, address);
// My own manager class to handle all the sockets connected
WebSocketManager manager = new WebSocketManager(this);
Socket connection = null;
while(bContinue)
{
connection = server.accept();
if(bContinue) {
// assign the socket to a new thread and start
// that thread
manager.newSocket(connection);
} else {
connection.close();
}
}
Is is possible that I'm using the wrong objects for sending the data back.
Should I even be using a bufferedwriter and reader? I had thought that these were the best way to go but now I'm not so sure.
It's important to note that this does not happen all the time, just sporadically. It could be the clients code having bugs but I need to make sure that I'm doing it correctly before going back to them.
This code is run on a Linux Ubuntu server. Logging occurs to a text file, nothing special there. My log files show the Send="" data going back to the client and no exception so it appears as if the .write and .flush() worked? Socket connections are persistant and only closed by the client and or network issues.
UPDATE ----- Client Side code -------:
I did manage to get some of the client side code for how they are handling the send and receiving of data (just in case it's more obvious on their end). The client is actually connecting to this server via an Android device (if that helps).
Creation of socket
static final int BUFFER_SIZE = 20000; // Maximum packet size
java.net.InetAddress server = java.net.InetAddress.getByName(url);
socket = new Socket(server, port);
// Set socket options:
socket.setReceiveBufferSize(BUFFER_SIZE);
socket.setSendBufferSize(BUFFER_SIZE);
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
Sending:
try {
// Send the packet:
OutputStream stream = socket.getOutputStream();
stream.write(p.getByteArray ());
stream.flush();
// Update the time:
lastPacketSendTime = new Date ();
} catch (IOException e) {
setError("Error sending packet (" + e.getMessage() + ")", ERROR_IO);
return false;
}
Receiving:
socket.setSoTimeout(timeout);
// Get the reader:
inputStream = socket.getInputStream();
while (true) {
// Get the next character:
int value = inputStream.read();
// Check for -1, indicating that the socket is closed:
if (value == -1) {
// The socket is closed remotely, so close it locally as well:
disconnect();
inputStream = null;
return null;
}
// ... and a bunch of other stuff to handle the actual data
}
EDIT 14-Nov:
This is actually proving to be more of a problem now. Both the client logs and the server logs appear to be sending. But at times the data doesn't appear to come through or if it does it is sometimes coming through 10 - 30 - 60 second delayed.
I can provide more information if required.
When you use BufferedReaders and BufferedWriters things get buffered. How about using the input and output streams directly.. Also, writers are character based, I don't know if you need to send binary data but if so that will be a problem with writers.
I am not sure whether this will be to your any use or not.. but i am giving you the code i used for client server communication..
Client Side:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket("127.0.0.1", 4444);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server Code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}