I'm trying to use a socket stream for multiple data transfers.
for sending a List<>
for sending text
...
Can I use just one socket for sending a String that tells the client what kind of data to expect, followed by the the expected data (in this case a List<>)?
Here's what I was thinking of:
//declarations
//outputs and inputs
private ObjectInputStream input;
private ObjectOutputStream output;
private OutputStream checkStatus;
private PrintWriter out;
...
private void forwardMessage(List<User> clients) throws IOException {
checkStatus = client.getOutputStream();
out = new PrintWriter(new OutputStreamWriter(checkStatus), true);
out.println("Command Option 1");
client.shutdownOutput();
output = new ObjectOutputStream (client.getOutputStream());
for (int i = 0; i < clients.size(); i++) {
output.flush();
output.writeObject(clients.get(i));
output.flush();
output.reset();
}
output.writeObject(null);
client.shutdownOutput();
}
The error given when I try this is "java.net.SocketException: Socket is closed"
I also tried to close the OutputStream but that gives the same result.
How can I use just one stream-socket for multiple data transfers?
If you are trying to send this data over a network, this might help:
http://systembash.com/content/a-simple-java-udp-server-and-udp-client/
then when it comes to detecting the data you could always do something like this:
if(name_of_your_string.compare("what_you_are_looking_for")){
//what you want to do with "what_you_are_looking_for"
}
Related
I've been making a chat room where multiple clients can connect and talk together on the same server. The only problem I'm having is getting each client to send more than one message. I've been trying different ways of looping the method to do so but I'm having some issues.
Any help would be appreciated :) thank you.
HERE'S THE CODE:
public class Client {
public static void main(String[] args){
Scanner clientInput = new Scanner(System.in);
try {
Socket SOCK = new Socket("localhost", 14001);
System.out.println("Client started!");
//Streams
while(true){
OutputStream OUT = SOCK.getOutputStream(); //writing data to a destination
PrintWriter WRITE = new PrintWriter(OUT); // PrintWriter prints formatted representations of objects to a text-output stream
InputStream in = SOCK.getInputStream(); //reads data from a source
BufferedReader READ = new BufferedReader(new InputStreamReader(in));
//---------------------------------
System.out.print("My input: ");
String atServer = clientInput.nextLine();
WRITE.write(atServer + "\n");
WRITE.flush(); //flushes the stream
String stream = null;
while((stream = READ.readLine()) != null){ //if stream is not empty
System.out.println("Client said: " + stream);
}
READ.close();
WRITE.close();
}
} catch (UnknownHostException e){
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
I've tried using a while loop to continuously ask for an input but doesn't seem to be working.
Are you making it out of the READ.readLine() while loop? Perhaps you're never getting an end of input character and thats never terminating. Also, you're closing both your READ and WRITE at the end of the while loop, and then expect them to be open on the next iteration. Move those and the close statements to the same layer as the Socket.
With that, every time you send something, your client is expecting something in response from the server. If you don't want them to be dependent on each other, I recommend moving the receive logic to its own thread in a while(true) loop.
My program is basically:
Client sends a String to Server,
Based on this String, Server is creating an ArrayList,
ArrayList is sent back to the Client.
What is failing here is:
After Client sends a String, the Server receives it and doesn't do anything else. In this time Client keeps on working and gets a NullPointer.
Client side:
public static ArrayList<String> sendStringToServer(String report) {
Socket socket;
ArrayList<String> fieldsList = new ArrayList<String>();
try {
socket = new Socket("localhost", 2345);
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os, true);
ps.println(report);
ps.flush();
//Here the debugger should stop and wait for server to create a List
//at this point there is no answer, code breaks
ObjectInputStream objectInput = new ObjectInputStream(socket.getInputStream());
Object object = objectInput.readObject();
fieldsList = (ArrayList<String>) object;
socket.close();
return fieldsList;
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Server side:
public class Server {
private ServerSocket serverSocket;
private Socket clientSocket;
private String telegram;
private StringBuilder telegramSB;
public static void main(String[] args) throws IOException, JRException {
new Server();
}
public Server() {
try {
serverSocket = new ServerSocket(2345);
while (true) {
clientSocket = serverSocket.accept();
InputStream is = clientSocket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
//debugger goes to here and then stops
telegram = br.readLine();
int counter = 0;
boolean startSeq = false;
for (char ch : telegram.toCharArray()) {
if (counter == 0 && ch == '/') {
startSeq = true;
}
if (startSeq == true) {
telegramSB = new StringBuilder();
telegramSB.append(ch);
}
if (ch == '\n') {
if (telegram.length() < 255) {
sendListWithFields();
} else {
new Launcher(telegram).run();
}
}
counter++;
}
} catch (JRException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
System.out.println(e);
}
}
My guess here would be that the BufferedReader is waiting to fill its buffer and you haven't sent enough data for it to do that and return so its waiting for more data to come through that never does (because your clients stops writing and starts to read). You could test this theory temporarily by dumping a load more data into the OutputStream on the client and flushing it.
If the above is the case then you probably want to not use BufferedReader but you have other issues here which also mean you probably want to avoid using PrintStream and BufferedReader for communication and serialisation anyway. For example the default character encoding on two different machines and JVMs could be different. When you create your PrintStream and InputStreamReader you don't specify a character encoding so they could end up being mismatched and the string that you write (including the newline character) could end up being understood completely differently by the remote side, this could also be a reason why its blocking (the client side encodes the newline character in one way but the server is expecting it to be encoded a completely different way), though less likely I think .
If you don't have to use PrintStream then I would suggest instead using DataOutputStream / DataInputStream:
//Client
BufferedOutputStream bufout = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dout = new DataOutputStream(bufout);
dout.writeUTF(report);
dout.flush();
//Server
BufferedInputStream bufin = new BufferedInputStream(socket.getInputStream());
DataInputStream din = new DataInputStream(bufin);
String report = din.readUTF();
You still get buffering from the BufferedIn/OutputStreams so it will be performant but the DataIn/OutputStreams will manage termination of variable length objects for you - they will send a length prefixing the string to tell the other side exactly how many bytes to read, so you don't need to use a special character to terminate the string you wrote, and this also means it doesn't matter what the content of your String is. In your example above even if it was working if your String had a newline character in it the server would read up until that first newline character, not to the end of the string you sent and that would put them out of sync for the next send/receive along that stream.
Using write/readUTF also specifies an encoding (UTF-8) so there is no mismatch there either.
First of all, this is a homework problem. That being said, I'm stuck. Googling for java Properties over Sockets results in a lot of irrelevant things.
I'm trying to transfer a Properties object over a socket. The API says it can be done with a Stream or a Writer/Reader, but I can't get it to work. I can do it manually, that is, if I read the file line by line and pass it through a PrintWriter.
On the client side I've got roughly:
socket = new Socket(host, port);
outStream = socket.getOutputStream();
out = new PrintWriter(outStream, true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader = new BufferedReader(new FileReader(file));
...
props.load(reader);
props.store(out, null);
On the server side the receiving bits look like:
out = new PrintWriter(sock.getOutputStream(), true);
inStream = sock.getInputStream();
in = new BufferedReader( new InputStreamReader(inStream));
...
props.load(in); // hangs
// doesn't get to code here...
In this case it hangs at the props.load(in). Instead of doing props.load(in), I read it in line by line to make sure props.store(out, null) was working, and the data looks like its being transferred.
Is there something about load/store I don't understand, or is it an issue with the Stream/Writer/Reader?
I think this will answer this question as well as How do I recognize EOF in Java Sockets? and What can I send to an InputStream to signify EOF has been reached?
I had a similar problem; my dilemma was that I had a client/server request-response protocol where one of the requests included a stream sent from the client side using clientProps.store(). The corresponding serverProps.load() on the server side never returns because it needs to see the "end-of-file" - which in Java means the client has to close it's stream; resulting in the socket connection closing. The unwanted result was that, not only could I not keep the socket open for indefinite request-response exchanges, I couldn't even keep it open for the server to send its reply.
I hated Java for making me do that, even more because the documentation for Properties.load() says:
The specified stream remains open after this method returns.
That could never happen if it's detecting end-of-file by seeing the stream close!! Anyway, now, I still love Java because it allowed me to use this solution (might not be useful if you have any special encoding or localization of the data you are streaming):
I used this on the client side:
PrintWriter toServer;
Properties clientProps = new Properties();
// ... code to populate the properties and to
// construct toServer from the socket ...
clientProps.store(toServer, null);
toServer.write('\u001A'); // this is an old-school ASCII end-of-file
toServer.flush();
On the server side I extended Reader to detect the 1A and return -1 (so that the serverProps.load() learns about the end-of-file in the normal way (by seeing -1 returned from a call to read()), but below that, the stream and the socket stay open.
BufferedReader fromClient;
Properties serverProps = new Properties();
// ... code to construct fromClient from the socket ...
serverProps.load (new PropReader (fromClient));
/////
private static class PropReader extends Reader {
BufferedReader src;
boolean eof=false;
private PropReader(BufferedReader fromClient) {
super();
src=fromClient;
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
int inCount;
if (!eof) {
inCount = src.read(cbuf, off, len);
if (inCount > 0) {
// we read a buffer... look at the end for the EOF that the client used to mark the end of file
if (cbuf[off+inCount-1] == '\u001A') {
--inCount; // don't send eof with the data
eof = true; // next time... we'll return -1
}
}
} else {
inCount = -1;
}
return inCount;
}
#Override
public void close() throws IOException {
src.close();
}
I ran into a problem while using input/output streams in Java. My thought was to have a DataInputStream to handle receiving text and a PrintStream to pass messages to the server from the server and object(output/input)streams to handle passing piece movements and current board image.
My problem is that the code hangs while it is trying to create the ObjectInputStream in the code below. Is this because I am trying to have multiple input and output streams? If so is there any possible fix I could use?
Socket sock = new Socket("127.0.0.1", 1716);
input = new DataInputStream(sock.getInputStream());
printer = new PrintStream(sock.getOutputStream());
System.out.println("Test 1");
zelda = new ObjectInputStream(sock.getInputStream());
System.out.println("Test 2");
link = new ObjectOutputStream(sock.getOutputStream());
System.out.println("Test 3");
I have a lot of Legend of Zelda references in my server source code and the code is rather large. The previous source code is for the client and although the server connects here is where I call ObjectOutputStream.
ObjectOutputStream ganandorf;
for(int i = 0; i < clients.size(); i++)
{
try
{
ganandorf = new ObjectOutputStream(clients.get(i).getOutputStream());
ganandorf.write(1);
ganandorf.flush();
ganandorf.writeObject(something);
ganandorf.flush();
}
Don't try to use two different kinds of streams/readers/writers on the same underlying connection. You will encounter buffering issues at both ends that make it basically impossible.
I would use ObjectInputStream and ObjectOutputStream and just write objects.
The constructor of ObjectInputStream blocks until it receives the header that is written by the constructor of ObjectOutputStream, so if you are constructing both you must construct the ObjectOutputStream first. You don't need to write anything and you don't need to flush it either, it does that itself.
I think you can only ask for 1 inputStream reference:
InputStream baseInputStream = sock.getInputStream();
input = new DataInputStream(baseInputStream);
zelda = new ObjectInputStream(baseInputStream);
same goes for outputStreams
I never found out what happened with ObjectInputStream, but I switched to DataInputStream and I'm currently modifying my code so it sends the piece name, x location, and y location in one string that will get broken up at the client and the board will be modified accordingly
Open a socket on a different port and use that to create new streams.
I know that there is a good variant to use Scanner object when you need to get data from server during connetion. But I have question about the following code snippet:
public void sendMessage(String message) {
try {
OutputStream os = socket.getOutputStream();
try {
byte[] buffer;
buffer = message.getBytes();
os.write(buffer);
} finally {
os.close();
}
InputStream is = socket.getInputStream();
try {
StringBuffer data = new StringBuffer();
Scanner in = new Scanner(is);
while (in.hasNext()) {
data.append(in.next());
}
System.out.println(data.toString());
} finally {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
I'm confused by the snippet where Scanner gets data from InputStream, because it starts just after I send a message to the Server. Is it fair to suppose that data from the Server won't be in InputStream immediatelly after sending message to it?
Please, give me an advice, what is the best way to make reading data from InputStream in such case and what I should to take into consideration?
The InputStream.read() method called by Scanner blocks until there is some data available. So you don't have to worry about the response time of the server.
See: http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#getInputStream()
The code is invalid. All it does is read as much input as can be read without blocking. There is no implication that what has been read is a complete message, or corresponds to a single write() invocation at the sender, etc. If you want messages in TCP/IP you must implement them yourself, with a length word prefix, a self-describing protocol such as Object Serialization or XML, etc. etc.