how to tell server has sent data successfully in socket programming? - java

i am working on a problem on socket programming in JAVA.
There is a server and a client.
1) server is connected to client
2) server sends N no of Strings which are stored in an array on server side(obviously ;)).
3)Client doesn't know the size of array
4)Server receives Strings from server one by one.
5)When Client reads all the Strings it sends one msg to server
6)Server receives the msg.
7)This process goes on(step 2-step 6) for multiple times.
The problem i am facing is, Client does not know when server sends the last String and it is waiting for its turn.
I have solved this problem using:
a)Multi threading.
b)Telling size of array to client at the beginning of the first msg
I want to know is there any in-built function which indicates if the server has stoped sending data?
here is the code for 1 iteration(step 1-step 6)
Server code:
public class server {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static ServerSocket server;
static Socket socket;
public static void main(String[] args)
{
a=new String[]{"String1","String2","String3"};
try {
server=new ServerSocket(8080);
socket=server.accept();
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
///sending array values
//String temp=null;
for(int i=0;i<a.length;i++)
{
dos.writeUTF(a[i]);
}
String msg_from_client=dis.readUTF();
System.out.println(msg_from_client);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client code:
public class client {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static Socket socket;
static Scanner sc;
public static void main(String[] args)
{
try {
socket=new Socket("127.0.0.1",8080);
System.out.println("connected");
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
sc=new Scanner(System.in);
//reading from server i dont know what is the size of array at server side
String temp=null;
while((temp=dis.readUTF())!=null)
{
System.out.println(temp);
}
System.out.println("out of the loop");
////now client sends the msg;
String msg=sc.nextLine();
dos.writeUTF(msg);
System.out.println("sent");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
output at client side:
connected String1 String2 String3

This is the time to learn more about protocols. You can setup your own protocol between your server and client i.e., the first message from the server would always contain the # of strings to follow. The client would keep a note of it and then it will request for # of strings that server told in first method.
EDIT: Little more enhanced protocol
If you chose the path to open a new connection for each message as suggested by other user, then you would have to add a little more to your protocol. You would need
Client Information, so that server knows what communication it has done with this client previously
Message information, so that server knows if this client is asking for new message or it sent some message earlier to this client and he is asking for next part of this message.
1 can be achieved by allotting a client ID. If you know how many clients you are dealing with, you can have it a hardcoded value. Otherwise generate at runtime
2 Message information could be "null" indicating that the client is asking for "any new message" for him. Keep in mind that having a "null" message_id doesn't mean that you skip this field. You have to make sure you add "message_id" "key" in the request but keep that field empty. The reply to this request would be expected # of strings that server would be returning plus a newly generated message_id. The client will use this message_id in all subsequent calls and will tell the server, I am asking for string x of y from message_id z

You need absolutely to exchange one information between server and client to indicate end of transmission:
by sending number of message before: as you suggest;
by sending special message at the end "END" for example.
Another solution: instead of looping 6/7, close the connection when data is read, and connect again.

Related

I'm misunderstanding something on how to set up sockets, but I'm not suer if it's client side, server side, or both

I'm setting up a simple program to test starting a server, and I'm getting a silent failure state. My client seems to think it has sent, while my server doesn't think it's recieving. The two are managing the initial connection, it's just sending things after that where it's failing.
I've cut things down to the core of where it's currently failing I think.
Here's part of the Client code
public void Client (int port, String ip)
{
try {
sock = new Socket(ip, port);
System.out.println("Found the server.");
streamInput = new DataInputStream(sock.getInputStream());
// sends output to the socket
streamOutput = new DataOutputStream(
sock.getOutputStream());
streamOutput.writeChars("Client Begining Conversation");
System.out.println(streamInput.readUTF());
}
catch (UnknownHostException u) {
System.out.println(u);
return;
}
catch (IOException i) {
System.out.println(i);
return;
}
}
public static void main(String[] args) throws IOException {
// create the frame
try {
ClientGui main = new ClientGui();
main.Client(8000,"127.0.0.1");
main.show(true);
} catch (Exception e) {e.printStackTrace();}
Here's server code.
public Server(int port) throws Exception
{
ServerSocket gameServer = new ServerSocket(port);
Socket gameSocket = gameServer.accept();
System.out.println("Client has connected");
// to send data to the client
PrintStream dataOutput
= new PrintStream(gameSocket.getOutputStream());
// to read data coming from the client
BufferedReader reader = new BufferedReader( new InputStreamReader(
gameSocket.getInputStream()
));
//play logic
Play(reader,dataOutput);
public void Play(BufferedReader reader, PrintStream dataOutput) throws Exception
{
String received, textSent;
System.out.println("Waiting for response.");
received = reader.readLine();
System.out.println("Client has responded");
//contenue until 'Exit' is sent
while (received != "Exit" || received != "exit") {
System.out.println(received);
textSent = received + "recieved";
// send to client
dataOutput.println(textSent);
}
}
My client gets to here -
Found the server.
and my server gets to here -
Trying to start server.
Client has connected
Waiting for response.
At which point, it just hangs forever, each side waiting for the other. It doesn't throw an error, it just... waits until I force it closed.
So it appears that I'm either doing something wrong when I send with "streamOutput.writeChars" in my client, or I'm doing something wrong when I receive with my server with "reader.readLine();", but I can't figure out what.
Or I could be doing something more fundamentally wrong.
The problem is that reader.readLine() doesn’t return until it sees a new line character, but streamOutput.writeChars("Client Begining Conversation") doesn’t send one.
More generally, mixing a DataOutputStream on the client with a BufferedReader on the server won’t work reliably, as the latter expects plain text, while the former produces formatted binary data. For example, the character encoding might not match. The same applies to communication in the opposite direction with PrintStream and DataInputStream. It’s best to pick either a text based or binary protocol and then be consistent about the pair of classes used on both the client and server.
In the case of a text protocol, an explicit character encoding should be defined, as the default can vary between platforms. As a learning exercise, it might not matter, but it’s a good practice to be explicit about specifying a character encoding whenever handling networked communication. UTF-8 is a good choice unless there’s a specific reason to use another one.
In addition, it is generally preferred to use PrintWriter instead of PrintStream for text output in new code. Read this answer for an explanation.

Unresponsive socket read buffer

I am trying to send data to one of my servers and receive an ACK back from it. However, the processing gets hung up when waiting for a response from the server. I know for a fact that there is a connection because I can see the data reaching the server. I also know that the server is outputting data correctly because my C# client is receiving data back from the server. I will note that this client is running on a centOS virtual machine. The server is a remote windows machine. I wouldn't imagine that there would be an issue due to the virtual environment because I am able to use an SNMP java client (SNMP4j package) to make calls to a remote server. I believe my server is outputting raw binary too, but I would expect to see some kind of output either way.
// A Java program for a Client
import java.net.*;
import java.io.*;
public class Client
{
// initialize socket and input output streams
private Socket socket = null;
private DataInputStream input = null;
private DataOutputStream out = null;
private DataInputStream serveroutput= null;
// constructor to put ip address and port
public Client(String address, int port)
{
// establish a connection
try
{
socket = new Socket(address, port);
System.out.println("Connected");
// takes input from terminal
input = new DataInputStream(System.in);
// sends output to the socket
out = new DataOutputStream(socket.getOutputStream());
serveroutput = new DataInputStream(socket.getInputStream());
}
catch(UnknownHostException u)
{
System.out.println(u);
}
catch(IOException i)
{
System.out.println(i);
}
// string to read message from input
String line = "";
// keep reading until "Over" is input
while (!line.equals("Over"))
{
try
{
line = input.readLine();
out.writeUTF(line);
System.out.println(serveroutput.readLine())
}
catch(IOException i)
{
System.out.println(i);
}
}
// close the connection
try
{
input.close();
out.close();
socket.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
Could be great if you would share the otherside codes. (sorry cannot comment yet)
Try use something else over writeUTF(), simply maybe a PrintStream, as mentioned by #marquis-of-lorne (read|write)UTF may be confusing by the peer.
Also this might be a good practice to flush() out the output from both side when there is nothing else to send to make sure data is sent completely.
You may also try BufferedReader over InputDataStream as you are trying to read lines. readLine() from InputDataStream is deprecated.

How to queue clients and serve them one at a time without using any threads?

I'm trying to create a socket programming application that gives returns the evaluation of a math expression to the client based on input from the client to the server. It should serve which means if there is a client being served and another client want to connect it should be queued. After the client is done (types quit) it pick up the next client and serve them. I'm really stuck on trying to serve the other client as when the first client is done the connection just resets and the second client is never severed.
From what I've seen the second client is connected and is in the backlog (goes to 50 by default) so I'm trying to find out how I can pick up and serve that client. I've pasted part of the server code which I believe is the culprit. I'm avoiding using threads entirely for this task.
import java.net.*;
import java.io.*;
public class TCPMathServerPersistent {
private static int PORT = 5000;
public static void main(String[] args) {
try {
#SuppressWarnings("resource")
ServerSocket server = new ServerSocket(PORT);
System.out.println("This is the TCP Server.");
while (true) {
Socket connectionSocket = server.accept();
System.out.println("Client accepted.");
DataInputStream in = new DataInputStream(connectionSocket.getInputStream());
DataOutputStream out = new DataOutputStream(connectionSocket.getOutputStream());
while (true) {
String line = in.readUTF();
String newLine = Double.toString(eval(line));
out.writeUTF(newLine);
out.flush(); // flushed the output stream and forces any buffered output bytes to be written out (done to improve performance)
}
}
}
catch(IOException e) {
}
}
}
I would not use the second while loop. Does not seem like you need it and as it says while(true) the loop does not stop and the other loop cant go on, so the other client cant be accepted

unable to receive all datagrampackets

Goodevening everyone.
I am trying to create an application using Eclipse(Kepler) where I send an array of DatagramPackets. My server side application is receiving all packets sent by the client. But when the server tries to respond back by sending the response packets back to client, my client is unable to receive all the packets.
I would be really obliged if someone helped me out.
here is my client side application code:
public static void main(String [] args) throws IOException
{
timing t=new timing(); // timing is the name of my class
InetAddress inet;
DatagramSocket ds;
int k=1024*60;
DatagramPacket[] p=new DatagramPacket[64];
DatagramPacket []recd=new DatagramPacket[64];
byte[] buf=new byte[1024*60];
if(args[0]==null)
{
args[0]="localhost";
}
inet=InetAddress.getByName(args[0]);
ds=new DatagramSocket(6443);
for(int i=0;i>64;i++)
{
p[i]=new DatagramPacket(sent.getBytes(),sent.length(),inet,7443);
recd[i]=new DatagramPacket(buf,buf.length);
}
ds.setSoTimeout(120000);
int buffer=ds.getReceiveBufferSize();
int j=ds.getSendBufferSize();
while(h<64)
{
p[h]=new DatagramPacket(sent.getBytes(),sent.length(),inet,7443);
ds.send(p[h]);
System.out.println("Client has sent packet:"+h);
h++;
}
System.out.println("Receiving.");
h=0;
while(h<64) // UNABLE TO RECEIVE ALL SERVER SIDE PACKETS . PROBLEM CODE
{
recd[h]=new DatagramPacket(buf,buf.length);
ds.receive(recd[h]);
System.out.println("Client has recd packet:"+h);
h++;
}
SERVER SIDE APPLICATION:
try{
byte[] buf=new byte[60*1024];
InetAddress add=InetAddress.getByName("localhost");
for(int i=0;i<64;i++)
dp[i]=new DatagramPacket(buf,buf.length,add,6443);
ds.setSoTimeout(120000);
System.out.println("SERVER READY AND LISTENING PORT 6443");
int h=0;
while(h<64)
{
dp[h]=new DatagramPacket(buf,buf.length,add,6443);
ds.receive(dp[h]);
System.out.println("Packet "+h+"recd.");
h++;
}
String x1=new String(dp[63].getData());
System.out.println("Server recd:"+x1);// correct. no problem here
InetAddress add2=dp[63].getAddress();
int port=dp[63].getPort();// this is fine. same data sent in all packets
h=0;
while(h<64)
{
dp[h]=new DatagramPacket(buf,buf.length,add2,port);
ds.send(dp[h]);
System.out.println("Server has sent packet:"+h);
h++;
}
kindly help me as when i send a single datagrampacket its being recd. but this array of packets isnt.
I do not know much about your code, but if I really want this 'for' loop:
for (int i=0;i>64;i++)
to be executed at least once I would change it to i<64.
You don't show what sent is in the client, or therefore how long it is, but I suspect it is some reasonable size that can actually be sent.
By contrast, in the server you are attempting to send 60k datagrams, which won't work unless the sender's socket send buffer and the receiver's socket receive buffer are at least that size.

Checking for a client disconnect on a Java TCP server - output only

I have a Java TCP server which, when a client connects to it, outputs a message to the client every 30 seconds. It is a strict requirement that the client does not send any messages to the server, and that the server does not send any data other than the 30-second interval messages to the client.
When I disconnect the client, the server will not realise this until the next time it tries to write to the client. So it can take up to 30 seconds for the server to recognise the disconnect.
What I want to do is check for the disconnect every few seconds without having to wait, but I am not sure how to do this given that a) the server does not receive from the client and b) the server cannot send any other data. Would anyone please be able to shed some light on this? Thanks.
Even though your server doesn't "receive" from the client, a non-blocking read on the client socket will tell you that either there's nothing to be read (as you expect), or that the client has disconnected.
If you're using NIO you can simply use a non-blocking Selector loop (with non-blocking sockets) and only write on your 30 second marks. If a SelectionKey is readable and the read on the SocketChannel returns -1 you know the client has disconnected.
EDIT: Another approach with blocking is simply to select with a 30 second timeout. Any client disconnects will cause the select to return and you'll know which ones those are via the read set. The additional thing you'd need to do there is track how long you were blocked in the select to figure out when to do your writes on the 30 second mark (Setting the timeout for the next select to the delta).
Big Edit: After talking to Myn below, offering complete example:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Set a 1 second timeout on the socket
clientSocket.setSoTimeout(1000);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream()));
long myNextOutputTime = System.currentTimeMillis() + 30000;
String inputLine = null;
boolean connected = true;
while (connected)
{
try {
inputLine = in.readLine();
if (inputLine == null)
{
System.out.println("Client Disconnected!");
connected = false;
}
}
catch(java.net.SocketTimeoutException e)
{
System.out.println("Timed out trying to read from socket");
}
if (connected && (System.currentTimeMillis() - myNextOutputTime > 0))
{
out.println("My Message to the client");
myNextOutputTime += 30000;
}
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
Worth noting here is that the PrintWriter really moves you far away from the actual socket, and you're not going to catch the socket disconnect on the write (It will never throw an exception, you have to manually check it with checkError()) You could change to using a BufferedWriter instead (requires using flush() to push the output) and handling it like the BufferedReader to catch a disco on the write.
If you are managing multiple clients then I guess you would be using Non-Blocking sockets (If not then consider using Non-Blocking). You can use Selector to monitor all the connected sockets to check if they are readable or writeable or there is some Error on that socket. When some client disconnects, your Selector will mark that socket and will return.
For more help google "Socket Select function"

Categories

Resources