Advice and Help Troubleshooting Client/Server Interaction for Cellular Modem Project - java

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).

Related

server thread show connection problems

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)

java DataInputStream read() stop and do not proceed

I want sends and receive an object and file the order is
client -> server by ObjectOut(In)putStream
client -> server String(file name) by DataIn(Out)putStrean writeUTF
client -> server by BufferedIn(Out)putStream
server -> client by ObjectOut(In)putStream
but when the code reaches on 3 writing file takes forever (I think...it is waiting) the critical code is
byte[] data = new byte[BUFFER_SIZE];
while ((length = bis.read(data)) != -1) {
bos.write(data, 0, length);
System.out.println(length);
}
bis(BufferedInputStream).read() do not proceed when I print the length the output is
4096
4096
879
then just wait...
is there anyone who knows what is the problem or solution?
Server thread
public void run() {
System.out.println("\n New FileUploadServer thread started");
msg = (Message) objComm.recvObject(clientSocket);
System.out.println("server get message");
if (checkState(msg.getState()))
System.out.println(clientAddr + " session over");
System.out.println("");
}
private boolean checkState(int _state) {
switch (_state) {
case ST_EXCEL_FILE:
return receiveExcel();
default:
return false;
}
}
private boolean receiveExcel() {
Message sendMsg = receiveStr();
System.out.println("receiveStr() success");
BufferedInputStream bis;
DataOutputStream dos;
DataInputStream dis;
FileOutputStream fos;
BufferedOutputStream bos;
VoteInfo sendVoteInfo = (VoteInfo) msg.getObj();
try {
dis = new DataInputStream(clientSocket.getInputStream());
dos = new DataOutputStream(clientSocket.getOutputStream());
// check file name extension is "xls" or "xlsx"
String fName = dis.readUTF();
int idx = fName.lastIndexOf(".");
String extension = fName.substring(idx + 1, fName.length());
if (!excelFileCheck(extension))
return false;
dos.writeUTF("read_ok");
dos.flush();
System.out.println("File name: " + fName);
File f = new File(EXCEL_FILE_DIR + fName);
fos = new FileOutputStream(f);
bos = new BufferedOutputStream(fos);
bis = new BufferedInputStream(clientSocket.getInputStream());
int length;
byte[] data = new byte[BUFFER_SIZE];
while ((length = bis.read(data)) != -1) {
bos.write(data, 0, length);
System.out.println(length);
}
bos.flush();
// send success message to web server
System.out.println("kangji2");
objComm.sendObject(sendMsg, clientSocket);
System.out.println("File receive success!");
if (!dataToDB.excelToDB(EXCEL_FILE_DIR + fName, extension)) {
//delete all db related to this excel file here
return false;
} else {
}
bos.close();
fos.close();
dis.close();
clientSocket.close();
// send candidates information to DB server
return makeResult(sendVoteInfo);
} catch (IOException e) {
System.out.println("ReceiveExcel error");
e.printStackTrace();
}
return false;
}
public class ObjectComm {
private Message receiveMsg = null;
private ObjectOutputStream out = null;
private ObjectInputStream in = null;
public Message commObject(Message _sendMsg, Socket _clntSocket) {
if (!_clntSocket.isConnected()) {
System.out.println("clnt Socket not connected");
return null;
}
try {
out = new ObjectOutputStream(_clntSocket.getOutputStream());
out.writeObject(_sendMsg);
out.flush();
System.out.println("kangji1");
in = new ObjectInputStream(_clntSocket.getInputStream());
receiveMsg = (Message) in.readObject();
System.out.println("kangji2");
return receiveMsg;
} catch (Exception e) {
System.out.println("commObject err");
e.printStackTrace();
return null;
}
}
public boolean sendObject(Message _msg, Socket _clntSocket) {
if (!_clntSocket.isConnected()) {
System.out.println("clnt Socket not connected");
return false;
}
try {
out = new ObjectOutputStream(_clntSocket.getOutputStream());
out.writeObject(_msg);
out.flush();
return true;
} catch (IOException e) {
System.out.println("Object comm send err");
e.printStackTrace();
return false;
}
}
public Message recvObject(Socket _clntSocket) {
if (!_clntSocket.isConnected()) {
System.out.println("clnt Socket not connected");
return null;
}
try {
in = new ObjectInputStream(_clntSocket.getInputStream());
receiveMsg = (Message) in.readObject();
return receiveMsg;
} catch (Exception e) {
System.out.println("Object comm recvObject err");
e.printStackTrace();
return null;
}
}
}
Did you close the connection in client side (sender side, or wherever opposite of your input stream) ? read(byte[], int, int ) in BufferedInputStream will return when end of the stream has been reached.
http://docs.oracle.com/javase/7/docs/api/java/io/BufferedInputStream.html#read(byte[],%20int,%20int)
client -> server by ObjectOut(In)putStream
client -> server String(file name) by DataIn(Out)putStrean writeUTF
client -> server by BufferedIn(Out)putStream
server -> client by ObjectOut(In)putStream
Too much stuff here.
Playing with streams at different levels of your stream stack simply does not work.
If you want to send objects, use the ObjectInput/OutputStreams for everything. Construct them as follows:
new ObjectOutputStream(new BufferedOutputStream(...))
and
new ObjectInputStream(new BufferedInputStream(...))
Send the objects with writeObject(); send the strings with writeObject() or writeUTF(); send byte arrays via ObjectOutputStream.write(); and use the complementary methods of ObjectInputStream at the other end.

Increase transfer speed of TCP socket in java /android

I am developing wifi direct based file transfer application. I can see that the transfer speed using TCP socket is not satisfactory. The speed is normally 1Mbps. Whenever I analyze the data transfer graph, I can see a lot of spikes and many seconds are with no data transfer at all. I know the transfer speed should be much higher (may be 20-30Mbps)
Please help me in increasing the transfer speed.
The serversocket that accepts the connection is
private void serverTask() {
Log.v(TAG, "server task");
try {
serverRunning = true;
ServerSocket serverSocket = new ServerSocket(
DeviceDetailFragment.PORT);
serverSocket.setReceiveBufferSize(TCP_BUFFER_SIZE);
Socket client = serverSocket.accept();
BufferedInputStream inputstream = new BufferedInputStream(
client.getInputStream());
// new BufferedInputStream(client.getInputStream(), 8 * 1024);
BufferedReader bufferedStream = new BufferedReader(
new InputStreamReader(inputstream));
fileName = bufferedStream.readLine();
fileSizeInBytes = bufferedStream.readLine();
fileMime = bufferedStream.readLine();
f = new File(Globals.fileSavingLocation + fileName);
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
if (f.exists()) {
f.delete();
}
f.createNewFile();
IOUtils.copy(inputstream, new FileOutputStream(f));
serverSocket.close();
}
isSuccessful = true;
} catch (IOException e) {
isSuccessful = false;
Log.e(TAG, e.getMessage());
}
serverRunning = false;
}
And the client that sends the data has following code:
private void clientTask(Intent intent) {
String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
String host = intent.getExtras().getString(EXTRAS_ADDRESS);
String fileName = intent.getExtras().getString(FILE_NAME);
String fileMimeType = intent.getExtras().getString(FILE_MIME_TYPE);
final long sizeInBytes = intent.getExtras().getLong(FILE_SIZE);
Socket socket = new Socket();
int port = intent.getExtras().getInt(EXTRAS_PORT);
try {
socket.setSendBufferSize(TCP_BUFFER_SIZE);
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)),
SOCKET_TIMEOUT);
BufferedOutputStream stream = new BufferedOutputStream(
socket.getOutputStream());
ContentResolver cr = FileTransferService.this
.getApplicationContext().getContentResolver();
InputStream is = null;
BufferedWriter bufferStream = new BufferedWriter(
new OutputStreamWriter(stream));
bufferStream.write(fileName);
bufferStream.newLine();
bufferStream.flush();
bufferStream.write(String.valueOf(sizeInBytes));
bufferStream.newLine();
bufferStream.flush();
bufferStream.write(fileMimeType);
bufferStream.newLine();
bufferStream.flush();
try {
is = new BufferedInputStream(cr.openInputStream(Uri
.parse(fileUri)));
} catch (FileNotFoundException e) {
isSuccessful = false;
}
IOUtils.copy(is, stream);
isSuccessful = true;
} catch (IOException e) {
Log.e(TAG, e.getMessage());
isSuccessful = false;
} finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
// Give up
e.printStackTrace();
}
}
}
}
The value of TCP_BUFFER_SIZE is set to 1024*512.
I have tried a lot altering the value of TCP_BUFFER_SIZE but with no luck. I replaced my implementation of copying stream by Apache Commons IOUtils.
Help me out
Update:
Please see the following transfer graph
It seems that you are overloading the buffer, from the setReceiveBufferSize() javadoc
It is possible to change the value subsequently, by calling
Socket.setReceiveBufferSize(int). However, if the application wishes
to allow a receive window larger than 64K bytes, as defined by RFC1323
then the proposed value must be set in the ServerSocket before it is
bound to a local address. This implies, that the ServerSocket must be
created with the no-argument constructor, then setReceiveBufferSize()
must be called and lastly the ServerSocket is bound to an address by
calling bind().
I would try a simple data transfer using a plain Socket without using files.
Have a simple server which sends 100 MB of empty data when you connect. Have the client read that data as fast as it can a report the throughput it got. On the same machine you should see over 100 MB/s easily. Once this gives a good number try it on an android client.

java client server multithreaded, works for only one connection

I did my client-server application but at the moment only one user can use it. Could you help me how to make it working for more than one user. I have the following functionality: On every two minutes counter is starting to decrease. Every user have 30 seconds to connect to the application. Every connected user should see same result with which he should make some other actions. I made it by this way at the moment. The code in the different cases is not so important. I need an advice how to make it working as a structure of the code. Thanks in advance!
import java.net.*;
import java.io.*;
public class MultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new MultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
import java.net.*;
import java.io.*;
import java.util.HashMap;
public class MultiServerThread extends Thread {
private Socket socket = null;
public MultiServerThread(Socket socket) {
super("MultiServerThread");
this.socket = socket;
}
public void run() {
try {
ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream fromServer = new ObjectInputStream(socket.getInputStream());
int userProcess = 0;
Object data = 11111;
boolean listening = true;
CountDown c = new CountDown();
int timeRemaining = 900;
while (listening) {
boolean send = true;
Object ob;
try {
ob = fromServer.readObject();
userProcess = Integer.parseInt(ob.toString());
HashMap<String,Integer> finalScores = new HashMap<String,Integer>();
if(userProcess == 0) {
timeRemaining = c.getRemainingTime();
int temp = 999;
while(timeRemaining-110>0) {
timeRemaining = c.getRemainingTime();
if(temp != timeRemaining) {
toServer.writeObject(timeRemaining-110);
toServer.flush();
temp = timeRemaining;
}
}
}
if(userProcess == 0 && timeRemaining-110 < 0) {
c = new CountDown();
send = false;
}
if(userProcess == 1) {
BoardGeneraor board = new BoardGeneraor();
data = board.getBoard();
}
if(userProcess == 2) {
int score = (Integer)fromServer.readObject();
String username = (String)fromServer.readObject();
finalScores.put(username, score);
data = finalScores;
c = new CountDown();
}
if(send) {
toServer.writeObject(data);
toServer.flush();
} else {
toServer.writeObject("quit");
toServer.flush();
}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
fromServer.close();
toServer.close();
socket.close();
} catch(IOException e) {
System.out.println(e);
}
}
}
I think your problem is that you have confused the server and client and have put the client and server code within the same Java file. It looks like you intend MultiServerThread to be the client, since it interprets the socket's output stream as going "to server" and the socket's input stream as coming "from server." But when you create a MultiServerThread with serverSocket.accept(), you're giving it a socket that represents the server's side of the connection to one client. Thus the output stream returned by socket.getOutputStream() represents a stream from the server to the client. What MultiServerThread should actually represent is one instance of the server talking to a client, not one instance of a client connecting to the server.
In order to have clients connect to your server, you'll need a separate Java file, say Client.java, containing a separate class with a separate main method. This class should open a connection to the server with the Socket(String host, int port) constructor, and treat the input stream of that socket as a stream of input from the server. Here's a simple example:
public class Client {
public static void main(String[] args) {
Socket serverConnection = null;
try {
serverConnection = new Socket("localhost", 4444);
} catch(IOException e) {
System.err.println("Could not connect to server");
System.exit(-1);
}
try {
ObjecttInputStream fromServer = new ObjectInputStream(serverConnection.getInputStream());
Object ob = fromServer.readObject();
} catch(IOException e) {
System.err.println("Error reading from server");
}
}
}
Once you've started your server by running the MultiServer.class file, you can start a client by running the Client.class file (in a separate window, while the server is still running).

Socket data does not appear to be getting through to client

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();
}
}

Categories

Resources