I have some problems with my server socket. I create a DatagramSocket to chat between a server and a client.
public static void main (String[] args) throws IOException {
byte[] send = new byte[1024];
byte[] receive = new byte[1024];
BufferedReader entree;
DatagramSocket serverSocket = null;
InetAddress ip;
InetAddress ipDest;
int port;
try {
serverSocket = new DatagramSocket(8888);
} catch (SocketException e) {
e.printStackTrace();
}
while (true) {
DatagramPacket recu = new DatagramPacket(receive, receive.length);
serverSocket.receive(recu);
String sentence = new String(recu.getData());
ipDest = recu.getAddress();
port = recu.getPort();
System.out.println("Reçu:"+sentence);
entree = new BufferedReader(new InputStreamReader(System.in));
String chaine = entree.readLine();
send = chaine.getBytes();
DatagramPacket dp = new DatagramPacket(send, send.length, ipDest, port);
serverSocket.send(dp);
send = new byte[1024];
receive = new byte[1024];
}
But I use new BufferedReader(new InputStreamReader(System.in)) get the next stuff to send, and it is blocking. So, I cannot receive what's comming from the client and print it.
How can I arrange this ?
Merci, eo
Trying to do non-blocking reads on System.in in Java is an exercise in futility. There's no portable way to do it, so Java doesn't support it.
Even if you create a separate thread and do a blocking read there, you'll have the problem of that thread being non-interruptible. See: Java: how to abort a thread reading from System.in
Basically, you either need to use a platform specific library (JNI) (JCurses for linux, for example), or use a GUI.
Edit to add: What you can do is move your socket reading to a different thread, as that is interruptible.
Related
I have written a client and server that are currently in an endless loop, that allow one message at a time to be sent and received. I need it to be able to continuously send/receive messages rather than be limited to one at a time.
Any idea on how I may go about this?
I am new to threads and not entirely sure how they work but i was thinking maybe a thread?
Client:
import java.io.*;
import java.net.*;
public class ClientChat {
DatagramSocket Socket;
public ClientChat(){
}
public void createAndListenSocket() throws SocketException, IOException{
while(true){
Socket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getLocalHost();
System.out.println("Type your message:");
BufferedReader message = new BufferedReader(new InputStreamReader(System.in));
byte[] incomingData = new byte[256];
String sentence = message.readLine();//"Testing from client";
byte[] data = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(data, data.length, IPAddress, 9876);
Socket.send(sendPacket);
System.out.println("Client: " + sentence);
DatagramPacket incomingPacket = new DatagramPacket(incomingData, incomingData.length);
Socket.receive(incomingPacket);
String reply = new String(incomingPacket.getData());
System.out.println("Server: " + reply);
//Socket.close();
}
}
public static void main(String[] args) throws IOException{
ClientChat client = new ClientChat();
client.createAndListenSocket();
}
}
Server:
import java.io.*;
import java.net.*;
public class ServerClient {
public void run() throws Exception{
DatagramSocket Server = new DatagramSocket(9876);
while(true){
byte[] buf = new byte[1024];
DatagramPacket incomingPacket = new DatagramPacket(buf, buf.length);
Server.receive(incomingPacket);
String message = new String(incomingPacket.getData());
System.out.println("Client: " + message);
System.out.print("Server: ");
BufferedReader response = new BufferedReader(new InputStreamReader(System.in));
String reply = response.readLine();
InetAddress IPAddress = incomingPacket.getAddress();
int port = incomingPacket.getPort();
byte[] data = reply.getBytes();
DatagramPacket replyPacket = new DatagramPacket(data, data.length, IPAddress, port);
Server.send(replyPacket);
}
}
public static void main(String[] args) throws Exception {
ServerClient Server = new ServerClient();
Server.run();
}
}
You are correct. You should use two threads - one for sending and one for receiving. You will also need two buffers to store the data while it's waiting to be send or processed after receiving. Most likely, you'll want FIFO buffers (a simple two-sided synchronized queue). Then, your main thread can only deal with reading/writing data to the queue, and the sending/receiving threads will take care of the rest in the background.
The sending thread should try to read from sending queue in a loop. The read operation on queue should block (pause the thread) until data is available.
The receiving thread should run in a loop to read a datagram from network and store it into a "received" queue. Reading datagram from network will block, while storing into a queue will return immediately unless the queue is full.
When the program is finished, you have to somehow "break" the threads from their loop. For example, you can set "shouldExit" boolean to true in your main thread, and check it in your send/receive threads. If you don't care, you can also set threads to daemon mode or just call System.exit().
Size your queues appropriately. If too small, messages will get lost and/or threads will be blocked a lot of time. If too large, you will waste memory. For example, estimate (or observe) the average and maximum number of messages in a queue, and add a safety margin.
I'm trying to create a server that reads the contents of a file and sends them to the client using datagram packets. Here's what I have so far:
public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {
BufferedReader br = new BufferedReader(new FileReader("File.txt"));
Scanner sc = new Scanner(new File("File.txt"));
DatagramSocket ds = new DatagramSocket();
while(sc.hasNextLine()){
DatagramPacket multi = new DatagramPacket(br.readLine().getBytes(), br.readLine().getBytes().length, InetAddress.getByName("224.0.0.5"), 7777);
ds.send(multi);
sc.nextLine();
sleep(1000);
}
}
When I run this, I get an error that says
Exception in thread "main" java.lang.IllegalArgumentException: illegal length or offset
The constructor I'm using is
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
Constructs a datagram packet for sending packets of length length to the specified port number on the specified host.
I do not understand why I am getting an error since I am passing the length as the second parameter.
Your code makes no sense whatsoever. You're setting the data of the DatagramPacket to the bytes of the next line, without checking for EOS, and you're setting its length to the length of the following line, and again without checking for EOS. So you can end up setting the length to less, or more, than the length of the data, neither of which makes sense, and you can encounter a NullPointerException at either step, which also makes no sense.
readLine() cannot possibly deliver the same thing twice in a row.
It also makes no sense whatsoever to use both a Scanner and a BuferedReader on the the same file, and to expect I/O done via one to affect the other.
You don't need to re-create a packet for each line of your text file.
Try this code.
public static void main(String[] args) {
try {
// Creaete a reader
BufferedReader reader = new BufferedReader(new FileReader("File.txt"));
//Create a socket
DatagramSocket socket = new DatagramSocket();
// Create a packet
byte[] data = new byte[1024]; // Max length
DatagramPacket packet = new DatagramPacket(data, data.length);
// Set the destination host and port
packet.setAddress(InetAddress.getByName("localhost"));
packet.setPort(9999);
String line = null;
while((line = reader.readLine()) != null){
//Set the data
packet.setData(line.getBytes());
//Send the packet using the socket
socket.send(packet);
Thread.sleep(200);
}
//Close socket and file
reader.close();
socket.close();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 7 years ago.
First i'm sorry for my english. :-) It's my first post here.
I have application, something like torrent. I run it in one computer but 2 or more instance. i must ask user what file he want, and send this file to client. if i want its be host-to-host or multi-host.
and my problem is: when i send to client list file in directory , he choose one of them and send to server nameFile. then server send this file to client. But when i send listFile i must close bufferedreader because readline() is blocking. but if i close that i don't have connection. Any idea?
please for any proposition. this is my code:
Server:
public class Server extends Thread {
private Socket s;
int numerKlienta;
String line;
List<String> list = new ArrayList();
private ServerSocket serverSocket;
String nazwaPliku = "";
PrintWriter outToClient;
String text = "";
String tmp = "";
public Server(int port) throws Exception {
serverSocket = new ServerSocket(port);
while (true) {
Socket clientSocket = serverSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
outToClient = new PrintWriter(clientSocket.getOutputStream(), true);
String path = "C:\\Users\\Ania\\Desktop";
File directory = new File(path);
File[] files = directory.listFiles();
for (int j = 0; j < files.length; j++) {
if (files[j].isFile()) {
text = files[j].getName();
outToClient.println(text);
}
}
//outToClient.flush();
outToClient.close(); //i must close beacuse in client when i writeBytes its blocking next steps
nazwaPliku = inFromClient.readLine();
System.out.println(nazwaPliku);
outToClient.close();
}
}
}
Client:
public class Client {
public Client(String host, int port) throws Exception{
s = new Socket(host, port);
DataOutputStream outToServer= new DataOutputStream(s.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new
InputStreamReader(s.getInputStream()));
System.out.println("lista plików w katalogu : ");
while ((( odpowiedz = inFromServer.readLine()) != null)){
System.out.println( odpowiedz);
}
//here is blocking and stop
System.out.println(" Jaki plik chcesz przesłać? podaj pełną nazwę");
Scanner sc= new Scanner(System.in);
String nazwaPliku=sc.next();
outToServer.writeBytes(nazwaPliku);
//saveFile(nazwaPliku);
}
And my Main:
public class Main {
public static void main(String[] args) throws Exception {
Server serwer=null;
System.out.println("Czy czy chcesz rozpocząc pracę jako serwer? (t/n)");
Scanner sc = new Scanner(System.in);
String odpowiedz = sc.next();
if (odpowiedz.equals("t")) {
System.out.println(" Na jakim porcie rozpocząc nasłuch?");
sc = new Scanner(System.in);
int portSerwera = sc.nextInt();
serwer = new Server(portSerwera);
//serwer.start();
}
else{
System.out.println("Czy chcesz rozpocząc połączenie z jakimś serwerem? (t/n)");
sc = new Scanner(System.in);
odpowiedz = sc.next();
if (odpowiedz.equals("t")) {
System.out.println("podaj numer portu do połączenia z serwerem");
sc = new Scanner(System.in);
int portKlienta = sc.nextInt();
Client fc = new Client("localhost", portKlienta);
You need to design a protocol with structured messages, instead of just sending lines. The client must know when a message ends.
For example you could decide to end your list of files by sending an empty line (1).
When the client reads the files, when it received the empty line, it knows that the list is terminated, and that it's up to the client to now send its choice.
Using separators is one way of doing. Another way can be to send "packets", where each packet starts with a number of bytes or characters to expect in the packet. The client thus knows that it must read N bytes to read the entire packet, and that once the packet is read, it should send its choice, and then read another packet (2).
(1) and (2): note that these two strategies are used by the protocol you probably use the most: HTTP. The header of an HTTP response ends with an empty line. And it usually contains the content length of the body of the response.
I'm developing a server to client file transfer program on java, and couldn't figure out how to fix the following code as I don't know much about socket programming. The code is Client side's codes:
String receiverIP = null;
int serverPort = 0;
hostIP = args[0];
serverPort = Integer.parseInt(args[1]);
String fileToSend = args[2];
byte[] aByte = new byte[1];
int bytesR;
Socket clientSocket = null;
Socket connectSocket = null;
BufferedOutputStream ToClient = null;
InputStream is = null;
try {
ToClient = new BufferedOutputStream(connectSocket.getOutputStream());
clientSocket = new Socket(hostIP, serverPort);
is = clientSocket.getInputStream();
} catch (IOException ex) {
System.out.println(ex);
}
as for my problem, I get a null pointer exception on line 14 (undoubtedly since currently connectSocket is null), but I have no idea what can I assign on connectSocket(if it was on server side a connection accept socket could've been assigned to begin writing after the connecion is established.)
Contrary to what you seem to believe, you do not need two separate sockets to read and write to the server. One socket will suffice. You can call the getInputStream method to get a stream to read from the server, and getOutputStream to get a stream to write to the server. You don't need two sockets, just one.
Just trying to get a handle on sockets. The server and client are running in two different programs.
They seem to be connecting fine to each other but the client will not properly send its output to the server. The server just hangs. Here's the code:
Server:
private ServerSocket serverSocket;
private Socket client;
public void run() throws Exception {
serverSocket = new ServerSocket(20005);
while(currentState == Game.State.NORMAL) {
client = serverSocket.accept();
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String clientInput = in.readLine();
// Takes the client input string and does some simple game logic that returns a Gson object
Gson serverResponse = processInput(clientInput);
out.write(serverResponse.toString());
out.flush();
}
}
Client:
Socket clientSocket;
void run() throws Exception {
clientSocket = new Socket("192.168.0.24", 20005);
PrintWriter out;
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Print the state of the game - returns false if state is win or lose.
while(printState()) {
out = new PrintWriter(clientSocket.getOutputStream(), true);
// This method just takes some input from the console
String clientInput = getInput();
out.write(clientInput);
out.flush();
String serverResponse = in.readLine();
updateState(serverResponse);
}
}
}
There is some underlying game logic that is happening but it's pretty minor and should be irrelevant. I imagine I am just misunderstanding something fundamental here.
Thanks all.
Make sure you send a newline character to match the in.readLine() statement in the Server.
out.write(clientInput + "\n");
The same applys when sending data from Server->Client.