I have created a simple class which sends a string to a server, both communicate using Java Sockets API. The server reads what the client have sent, and responds with another string. But the client can not read that response.
This is the client class:
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8181);
socket.getOutputStream().write("Hello".getBytes());
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.close();
}
}
And this is the server class:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8181);
while (true) {
Socket socket = serverSocket.accept();
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.getOutputStream().write("Hi!".getBytes());
}
}
}
I imagine that the problem may be in the client execution flow, because I don`t know how canI do it wait for a server response. In other words, how to implement a client able to read the server response?
You aren't closing the sockets.
The server is attempting to read until end of stream and then send a reply. End of stream only happens when the peer closes the connection, so it won't be possible to send a reply even after you fix (1). You need to read a message, whatever that means in your application protocol.
You need to flush or close the outputstream.
Related
To understand the concept of socket programming, I created a server and a client. The client will send a file and server should save it some location. (ie. a file upload).
Server:
package com.test.socket.server;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8081);
Socket socket = serverSocket.accept();
System.out.println("Received request");
InputStream inputStream = socket.getInputStream();
OutputStream out = new FileOutputStream("yoyo.png");
System.out.println("Reading....");
byte[] bytes = new byte[16 * 1024];
int count = 0;
while((count = inputStream.read(bytes)) > 0){
System.out.print(". ");
out.write(bytes,0,count);
System.out.println("Some bytes are written");
}
System.out.println("written....");
socket.getOutputStream().write("Written.....".getBytes());
out.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
Java client follows:
package com.test.socket.client;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class WebClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = null;
String host = "127.0.0.1";
socket = new Socket(host, 8081);
///home/renju/Desktop/frame.png
File file = new File("/home/renju/Desktop/frame.png");
InputStream inputStream = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[16 * 1024];
int count = 0;
while((count = inputStream.read(bytes)) > 0){
os.write(bytes);
}
System.out.println("Sending....");
os.close();
inputStream.close();
socket.close();
}
}
This works fine and writes the uploaded file to my projects root folder.
Now I changed the client to an HTML page.
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:8081/" method="POST">
<input type="file" name="file" />
<button type="submit" name="submit">Upload</button>
</form>
</body>
</html>
This is not working in the same fashion as the Java client. For some reason, the execution does not go beyond the out.write(bytes); of server code.
Console log..
Received request
Reading....
. Some bytes are written
What can be the possible reason?
One more question...
Ultimately what I am trying to understand is the purpose of 'multipart/form-data' while uploading a file(once I got the above code working, that is what I am planning to experiment). If someone could give me a hint on that, it will be really helpful.
This works fine.
No it doesn't. It writes junk at the end of the file, and possibly in other places as well. Your copy loop should be:
while((count = inputStream.read(bytes)) > 0){
System.out.print(". ");
out.write(bytes, 0, count);
}
in both server and client.
For some reason, the execution does not go beyond the out.write(bytes); of server code.
Actually it is blocking in read(), not write(). That is because you are now getting an HTTP request, and specifically it is because of HTTP keepalive. See RFC 2616 and successors. The server code you've written will write all the HTTP headers to the target file and then block until the client browser releases the connection, which can take an arbitrary amount of time. You need to read and parse the headers, specifically the Content-length and Content-encoding headers, and process the body of the request accordingly, which means only trying to read the number of bytes given in Content-length, not read to end of stream, and if the Content-encoding is chunked, you need to write some unchunking code.
From oracle docs:
A socket is one end-point of a two-way communication link between two
programs running on the network. Socket classes are used to represent
the connection between a client program and a server program. The
java.net package provides two classes--Socket and ServerSocket--that
implement the client side of the connection and the server side of the
connection, respectively.
Simple socket client is :
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
The Socket constructor used here requires the name of the computer and the port number to which you want to connect.
Simple socket server is:
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
ServerSocket is a java.net class that provides a system-independent implementation of the server side. To accept connection from client ServerSocket does:
clientSocket = serverSocket.accept();
I'm having trouble interpreting a question for a college assignment. It seems my solution is not an acceptable answer. I'm not looking for the solution just mainly an explanation on what I'm doing wrong.
The question is:
Implement a simple chat client which transmits user messages to a multicast address and receives messages sent from other clients on other machines sent to the same multicast address.
The way I am interpreting this is that I have is a server class with a multicast address, then n-amount of client classes that connect or join the server group.
Then when the client has connected to the server class. The server sends the same typed message out to the multiple clients which is displayed on screen of the client. Am I way off with whats asked??. My code for the multicast server is,
package multicastchatter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class multicastServer {
final static String INet_addr = "224.0.0.3";
final static int PORT = 8888;
public static void main(String[] args) throws InterruptedException, UnknownHostException {
InetAddress addr = InetAddress.getByName(INet_addr);
try(DatagramSocket serverSocket = new DatagramSocket())//open the datagram
{
for(int i = 0; i<5; i++)
{
String message = "Sent message number "+i;
//create a packet and send
DatagramPacket messPack = new DatagramPacket(message.getBytes(),message.getBytes().length, addr, PORT);
serverSocket.send(messPack);
System.out.println("The server says"+ message);
Thread.sleep(500);
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
and my multicast client is
package multicastchatter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
public class multicastClient {
final static String INet_addr = "224.0.0.3";
final static int PORT = 8888;
//final static int PORT = 8080;
public static void main(String[] args) throws UnknownHostException {
InetAddress address = InetAddress.getByName(INet_addr);//get address
byte[] buf = new byte[256];//create a buffer of bytes
//create the multicast socket
try(MulticastSocket clientSocket = new MulticastSocket(PORT))
{
clientSocket.joinGroup(address);//join the group
while(true)
{//recieve the info
DatagramPacket messPack = new DatagramPacket(buf, buf.length);
clientSocket.receive(messPack);
String message = new String(buf, 0, buf.length);
System.out.println("Socket recieved message saying" + message+ " by "+ messPack.getAddress());
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
Any advice is appreciated. All I can think off is that I need to send messages back to the server from the client?
Being that your question is asking if your conceptualization of the client-server architecture is correct, then yes. What your teacher wants is a server that accepts client connections, and broadcasts client messages it receives to all clients.
A multi-threaded server approach is typically chosen in this situation, as many concurrent connections are being utilized, and each of them waits for a message. Upon receiving the message, the server will take that message, append an identifier to the front so that we know what client said the message, and distribute that message once only to each client.
As for the client, it just takes input, sending when necessary, and always listens for packets from the server, displaying whatever it receives. A valuable word of advice:
Do not allow the client side to display what is sent until it is received. In other words, sending input from the client program should only display what was sent when it is received back from the server. It is a good practice to employ in server-client architecture in most instances.
Java code below:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Test {
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open(new InetSocketAddress(
"google.com", 80));
ByteBuffer buffer = ByteBuffer.allocate(1024);
while ((channel.read(buffer)) != -1) {
buffer.clear();
}
channel.close();
}
}
This code is easy.
But I did not write any data to Channel, so, it does not contain any data to reading.
In this case method channel.read() performed too long and do not return any data.
How do I handle this situation?
Thanks.
Update: Looking at your example you are connecting to a web server. The web server will not respond till you tell it what you want to do. For example doing a GET request.
Example (no proper character encoding):
public static void main(String args[]) throws IOException {
SocketChannel channel = SocketChannel.open(
new InetSocketAddress("google.com", 80));
channel.write(ByteBuffer.wrap("GET / HTTP/1.1\r\n\r\n".getBytes()));
ByteBuffer buffer = ByteBuffer.allocate(1024);
while ((channel.read(buffer)) != -1) {
buffer.flip();
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes);
System.out.print(new String(bytes));
buffer.clear();
}
channel.close();
}
If you don't want your reads to be blocking you would need to configure your channel as non-blocking. Otherwise it will sit and wait till data is available. You can read more about non-blocking NIO here.
channel.configureBlocking(false);
It's a blocking method. What did you expect?
You can set a read timeout on the underlying socket, or you can put the channel into non-blocking mode, probably in conjunction with a Selector.
I'm trying to make a simple HTML server that will read a request from my browser, parse the requested file from the request, then serve the appropriate HTML back to the browser. I need to be able to handle multiple requests, so I currently have a Server class acting as a parent of another runnable class RequestHandler. Each time a connection is made on the server, a new instance of the runnable class RequestHandler is run.
package server;
import java.io.IOException;
import java.net.ServerSocket;
public class Server {
public static void main(String[] args){
try{
ServerSocket serverSocket = new ServerSocket(8000);
for(;;){
Object block = new Object();
RequestHandler handler = new RequestHandler(block, serverSocket);
handler.start();
try{
synchronized(block){
System.out.println("Server thread paused...");
block.wait();
System.out.println("Server thread creating new RequestHandler...");
}
}catch(InterruptedException e){
System.out.println("Can't be interrupted!");
e.printStackTrace();
}
}
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class RequestHandler extends Thread {
Object block;
ServerSocket serverSocket;
BufferedReader socketReader;
PrintWriter socketWriter;
public RequestHandler(Object block, ServerSocket serverSocket){
this.block = block;
this.serverSocket = serverSocket;
}
#Override
public void run() {
try{
System.out.println("Waiting for request...");
Socket clientSocket = serverSocket.accept();
System.out.println("Connection made.");
synchronized(block){
System.out.print("Notifying server thread...");
block.notify();
System.out.println("...done");
}
socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
socketWriter = new PrintWriter(clientSocket.getOutputStream(), true);
String input;
while((input = socketReader.readLine()) != null){
System.out.println(input);
}
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
The problem I'm running into is that I'm not sure how to combine all the lines of the request so that I can parse the requested file. If it's just constantly waiting on request input, I'll never get to a point where I can parse the entirety of the request. How can I solve this problem?
your while loop will only break once the connection between the client and the server is closed. Since the client is waiting on the same connection for a response after sending the request the connection will remain open, so your readline() will block. In your while loop you have to check after every line whether you have reached the end of the request data. For GET requests, you have to look for a blank line following HTTP headers. For POST requests, you have to parse incoming headers looking for <Content-Length: N>. THen process the remaining headers looking for the blank line (just like in the GET case). Once you find the blank like, you have to read <N> bytes. At this point you know you've finished processing request data and should break out of the read loop.
Read the HTTP spec for details.
The first line gives you the request method as well as the requested path, the following lines are the request headers, the header block ends with a blank line.
That said, you are reinventing the wheel: you could use com.sun.net.httpserver.HttpServer
is there any small working program for recieving from and sending data to client using java nio.
Actually i am unable to write to socket channel but i am able to read the incoming data
how to write data to socket channel
Thanks
Deepak
You can write data to a socket channel like so:
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class SocketWrite {
public static void main(String[] args) throws Exception{
// create encoder
CharsetEncoder enc = Charset.forName("US-ASCII").newEncoder();
// create socket channel
ServerSocketChannel srv = ServerSocketChannel.open();
// bind channel to port 9001
srv.socket().bind(new java.net.InetSocketAddress(9001));
// make connection
SocketChannel client = srv.accept();
// UNIX line endings
String response = "Hello!\n";
// write encoded data to SocketChannel
client.write(enc.encode(CharBuffer.wrap(response)));
// close connection
client.close();
}
}
The InetSocketAddress may vary depending on what you're connecting to.