I have a client and a server, a classic example where trying to simulate in very simple way the http protocol. Firstly the client sends data while server prints the data and then the opposite. In the following code, either the server or client blocks, for an unknown reason.
The client sends to the server data, the server receive the data and prints it. But it just blocks after prints the data. If i close the outputstream of the client (out.close()) the client should get the server's data but instead throws IOException with the message: Socket closed.
My question is why is it blocking? Do i have to trigger the output with EOS?
CLIENT
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_client_webclient
{
public static void main(String [] args)
{
try{
Socket s = new Socket("localhost", 8080);
OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream());
InputStreamReader in = new InputStreamReader(s.getInputStream());
//WRITE
out.write("GET / HTTP/1.1\r\nUser-agent: Agent 2.0 Browser\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n");
out.flush();
out.close();
if (s.isConnected()==true && s.isClosed()==false) System.out.println("OPEN");
else System.out.println("CLOSED");
char[] bin = new char[400];
int r=0;
//READ
while((r=in.read(bin))!=-1) { System.out.println("Input data: "+r+" bytes"); System.out.print(bin); bin= new char[400]; };
System.out.println(r);
s.close();
}
catch (IOException ex) {System.out.println(ex.getMessage());}
}
}
SERVER
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_server_webserver
{
public static void main(String [] args)
{
while(true)
{
try{
ServerSocket server = new ServerSocket(8080);
Socket connection = server.accept();
try{
OutputStreamWriter out = new OutputStreamWriter( connection.getOutputStream());
InputStreamReader in = new InputStreamReader( connection.getInputStream());
char[] bin = new char[400];
int r=0;
int readsofar=0;
//READ
while((r=in.read(bin))!=-1) { System.out.print(bin); bin= new char[400]; };
System.out.println("END");
//WRITE
out.write("Server: BlockServer 1.0\r\nHost: 192.168.1.1\r\n\r\n");
out.flush();
System.out.println("Just written data to "+connection.getRemoteSocketAddress());
connection.close();
} catch (IOException ex) { connection.close();}
}catch (IOException ex) {}
}
}
}
Doing out.close() results in a socket closed exception because when you close an input/output stream, the socket related to it also gets closed. That means that in your client program, you won't be able to read in after closing the socket.
First, take out out.close() Instead of checking for -1, try creating an "exit"string. If the server reads the exit string, recognize that it needs to stop being in the while loop and just break; (can be done with a simple if statement). Also, usually I would use a buffered reader, String x and readLine() instead of a char array + read().
while (true) {
in.read(bin);
if (bin[0] == '^') { // or something like that
break;
}
System.out.print(bin);
bin = new char[400];
}
Only close() streams when you are finished with the socket entirely.
The server should not wait for the socket to get closed (because, once that happens, it won't be able to write back).
Instead of reading until it returns -1 (closed), it should read to the end of request (two new lines in case of http headers), and start sending output as soon as that happens, then, possibly, close the connection to inform the client that there is no more data (in http, the connection usually stays open for a while, the client knows to stop reading after enough bytes have been received according to Content-length header).
Related
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.
Hello i'm trying to execute a socket client in Java, but the client still reading the data and don't proceed with the program execution. Any ideas?
Here's the code:
import java.io.*;
import java.net.Socket;
public class SocketTeste {
public static void main(String[] args) {
try {
Socket client = new Socket("127.0.0.1", 1987);
System.out.println("Got connection");
DataInputStream handshake = new DataInputStream(client.getInputStream());
String handshakePure = handshake.readUTF();
System.out.println("Got the handshake");
System.out.println(handshakePure);
DataOutputStream saida = new DataOutputStream(client.getOutputStream());
saida.writeUTF("Got it!");
saida.flush();
saida.close();
String returnedData = handshake.readUTF();
System.out.println(returnedData);
handshake.close();
client.close();
} catch (Exception e) {
System.out.println("ERROR: " + e);
}
}
}
I don't think if that matter, but the socket server is a PHP socket server.
DataInputStream.readUTF expects a uniquely weird message format. The first two bytes it reads are interpreted as the length of the string to read, in a big endian binary format. This is then followed by a weird non-standard text encoding similar to but incompatible with UTF-8. Most likely you should not be using DataInputStream.readUTF to read data in a program, unless you used its counterpart DataOutputStream.writeUTF to write it in the first place.
Based on your comments it sounds like your communication protocol is based on lines of text. To read lines of text, you can use for example the BufferedReader class.
BufferedReader handshake = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
String handshakePure = handshake.readLine();
I need to merge two TCP packets into one. I wrote a socket emulator which reads a line of data from a csv file and outputs each line of data into two 99 byte binary packets every second. I now need to write another emulator that will merge these two 99 byte packets into one 198 byte packet.
This is what I put together so far and it basically forwards both 99 byte packets from one emulator and relays it to the client as two 99 byte packets. I have tried a couple different things but cannot seem to figure out how to merge the two into one 198 byte packet. Sounds simple, but i cannot wrap my head around it, suggestions will be greatly appreciated. Thanks
package PacketFuser;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class PacketFuser {
public static void main(String args[]) throws IOException{
//Start server
Socket socket = null;
final ServerSocket ss = new ServerSocket(6666);
System.out.println("Waiting on connection...");
while (ss.isBound()){
try {
socket = ss.accept();
System.out.println("Connected to port: " +socket.toString());
}
catch (IOException e){
}
//Start Client Socket
InetAddress address=InetAddress.getLocalHost();
Socket c1=null;
boolean client = false;
while (client == false){
try{
System.out.println("waiting on Emulator");
Thread.sleep(1000);
c1=new Socket(address, 31982);
client = true;
}
catch (IOException e){}
catch (InterruptedException ex) {}
}
System.out.println("Emulator Connected");
//I need to figure out here how to catch two packets and merge them into one 198 byte packets here.
DataInputStream in = new DataInputStream(s1.getInputStream());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int pread;
byte[] p1 = new byte[99];
while ((pread = in.read(p1, 0, p1.length)) != -1 ) {
buffer.write(p1, 0, pread);
buffer.flush();
socket.getOutputStream().write(p1);
}
}
}
}
Change new byte[99] for new byte[198].
probably a noobish Q:
So i made a very simple single-threaded server/client model. Now when i execute the program in the eclipse IDE it shows me System.out's of the server and not the ones from the client.
When i press terminate, the System.out.println lines that were supposed to be generated by Client show up.
I'm struggling with this for days now.. Hopefully someone can help me out.
Thanks in advance!
SERVER:
import java.net.*;
import java.io.*;
public class Server {
public static void main(String[] args)
{
new Server();
}
public Server()
{
try
{
ServerSocket serverSocket = new ServerSocket(8000); //nieuw instantie van een ServerSocket
System.out.println("Waiting for clients..");
Socket socket = serverSocket.accept(); // lister for socket requests
while(true)
{
BufferedReader inputClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
DataOutputStream clientOutput = new DataOutputStream(socket.getOutputStream());
String clientInput = inputClient.readLine();
System.out.println("Server: clientInput= : " + clientInput);
InetAddress hostAddress = InetAddress.getByName(clientInput);
String iPaddress = hostAddress.getHostAddress();
System.out.println("Server: IP = : " + iPaddress);
clientOutput.writeBytes(iPaddress);
clientOutput.flush();
}
}
catch(IOException ex)
{
System.err.println(ex);
}
}
}
CLIENT:
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
new Client();
}
public Client()
{
try
{
Socket socket = new Socket("localhost", 8000);
DataOutputStream toServer = new DataOutputStream(socket.getOutputStream());
BufferedReader fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
toServer.writeBytes("google.com" + '\n');
String ip = fromServer.readLine();
System.out.println("Client: "+ ip);
}
catch(IOException ex)
{
System.err.println(ex);
}
}
}
When you start a client and a server program, they will have 2 separate consoles. Only one is visible at a time in the "Console" view of Eclipse. That is why you only see the server's.
You can switch between the active consoles with the "Display Selected Console" icon (it's a monitor icon) and also see the active console list.
Also you have a full-duplex connection. Both the client and the server can read/write. You use a DataOutputStream - BufferedReader representation for a one-way communication which is WRONG.
DataOutputStream writes binary data, BufferedReader reads text (character) data.
You should use one of the following pairings:
DataOutputStream - DataInputStream and use writeUTF() and readUTF() methods
OR
PrintWriter - BufferedReader and use println() and readLine() methods
clientOutput.writeBytes(iPaddress);
clientOutput.write("\n".getBytes());
clientOutput.flush();
Just add these lines (second line) in your Server class.
Reason
In your Client class you are reading a line from buffer reader but you have not send any character from server indicating end of line. So in the second line we are writing new line character indicating end of line.
When you close the server, connection get reset and available input are read. Thats why your Client prints if you close the server.
Optionally if you only want to modify your Client class you can write these lines
char [] a = new char[100];
int length = fromServer.read(a);
System.out.println("Client: "+(new String(a)).substring(0,length));
Instead of these
String ip = fromServer.readLine();
System.out.println("Client: "+ ip);
Ok so after indexing the line with an '\n' and putting the line :
Socket socket = serverSocket.accept();
inside the while loop in stead of inside try{} i got rid of all my problems.
Thanks, now i'll try to multithread this thing!
Essentially what I'm trying to do is have a client (with an unknown IP) connect via socket to a server, and have the server send a BufferedImage back to the client every x seconds.
I understand how this can be done with a known client IP, but not with an unknown. A simple example would be awesome, thanks.
Example with known IP:
BufferedImage scr = getImage();
Socket sock = new Socket(ip, 123456); //unknown IP
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream(scr);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
bos.close();
sock.close();
Also, if anyone could show me where I could loop it to keep sending the file, that would be awesome.
I whipped up some sample server client connection. Basically you just define your server to use your localhost then port forward or open the server port depending on what your network configuration is. Thers lots of tutorials about that online. On your client you need to either know your external or internal IP address depending on where your connecting from.
This sample just uses your localhost and sends a file from your harddrive, but I wrote it specifically with the intended use of adding in any InputStream or OutputStream so you can adapt this to reading or writing an image. Most servers you will just bind your ip address to 127.0.0.1. When connection to the server outside your local network you will need to find your external IP address. You can find this on websites like whatsmyip.org.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class SendFileExample {
public static void main(String [] args) throws IOException {
System.out.print("Type 's' for server or 'c' for client: ");
char c = (char) System.in.read();
if(Character.toLowerCase(c) == 's') {
createServer();
} else if(Character.toLowerCase(c) == 'c') {
createClient();
}
}
public static void createServer() throws IOException {
// create a server to listen on port 12345
ServerSocket socket = new ServerSocket(12345, 0, InetAddress.getByName("127.0.0.1"));
System.out.println("Server started on " + socket.getInetAddress().getHostAddress() + ":" + socket.getLocalPort() + ",\nWaiting for client to connect.");
Socket clientConnection = socket.accept();
System.out.println("Client accepted from "+clientConnection.getInetAddress().getHostAddress()+", sending file");
pipeStreams(new FileInputStream(new File("c:\\from.txt")), clientConnection.getOutputStream(), 1024);
System.out.println("File sent, closing out connection");
clientConnection.close();
socket.close();
}
public static void createClient() throws IOException {
System.out.println("Connecting to server.");
Socket socket = new Socket();
// connect to an address, this is the server address (which you have to know)
socket.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 12345));
// read all bytes from the socket
System.out.println("Success, retreiving file.");
pipeStreams(socket.getInputStream(), new FileOutputStream(new File("c:\\to.txt")), 1024);
System.out.println("Done, file sent. Closing connection");
socket.close();
}
/**
* writes all bytes from inputStream to outputStream
* #param source
* #param out
* #throws IOException
*/
public static void pipeStreams(java.io.InputStream source, java.io.OutputStream destination, int bufferSize) throws IOException {
// 16kb buffer
byte [] buffer = new byte[bufferSize];
int read = 0;
while((read=source.read(buffer)) != -1) {
destination.write(buffer, 0, read);
}
destination.flush();
destination.close();
source.close();
}
}
I think the cleanest way to achieve this would be to have the client connect every x seconds to the server, and pull the image from the socket's stream.
If you want the server to have the initiative, have the client connect to the server, and then keep the socket open to send images every x second. This means that the client must be ready to read the images as they come. It also means that the length of an image must be sent before it's content, since the image is not terminated by the end of the stream.