I'm working on a project and i want to comunicate with a device. I made a socket connection with the device, the connection works but the device is sending me the message: 0xd7d0 and i have to write that message back. It's a keep alive message. I'm haveing trouble reading and sending back that message.
here's the code i've writen so far:
package Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
public static ServerSocket serverSocket;
public static void main (String [] args) {
try {
serverSocket = new ServerSocket(1234);
while (true) {
ServerThread serverThread = new ServerThread(serverSocket.accept());
serverThread.start();
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
package Server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ServerThread extends Thread {
public Socket socket;
public BufferedReader in;
public PrintWriter out;
public ByteBuffer buf;
int count;
public ServerThread (Socket socket) {
try {
this.socket = socket;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
} catch (IOException ex) {
Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
while (true) {
try {
count = in.read();
buf = ByteBuffer.allocate(100);
buf.put((byte) count);
buf.flip();
out.println(buf);
String line = in.readLine();
System.out.println(line);
} catch (IOException ex) {
Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Can anyone tell me what i am doing wrong?
This
while (true) {
ServerThread serverThread = new ServerThread(serverSocket.accept());
serverThread.start();
}
doesn't look right. You're looping and creating a new thread repeatedly (which will consume resources and create an enormous number of threads). You should simply create that thread once. If your program is doing nothing else then a new thread may be superfluous.
Your mistake is that you mix different styles of network data exchange. First, what format are messages in? Are they characters in some encoding, or some binary data? In the first case, you should not use Buffer to read message in, but read and write using in and out character streams you created already. In the second case, you have 2 options: read and write with socket and byte streams, or with channels from java.nio.channels and Buffers. To write back a message in a buffer, you can use
buf.flip();
buffer.position(buffer.limit());
Related
right now I have a java program that uses threads and sockets to echo text responses like a real chat window. Currently, my program works by running the server and than as many clients as I want. When a client enters a message, that message is echoed to the server and also to the client that sent the message.
My problem is that I want the message any client enters to be sent not only to the server and to themselves, but to every other client as well.
Heres how it currently works:
Server:
Received client message: test1
Client 1:
Enter message: test1
test1
Client 2:
Enter message:
Client 1 enters test1, receives test1 back and the server also receives test1. Client 2 gets nothing. My goal is to have any messages entered in the clients display on the client that sent the message as well as the other clients and server.
Working example:
Server:
Received client message: test1
Received client message: hello
Client 1:
Enter message: test1
test1
From client 2: hello
Client 2:
Enter message:
From client 1: test1
hello
The formatting doesnt have to be exactly like that, but thats the idea. My code so far is below. Ive read that I need to add my clients to a list and then loop over them and send them all the message but im not sure. Any help would be great.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Scanner;
public class EchoMultiThreadClient {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 4000)) {
//socket.setSoTimeout(5000);
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
Scanner scanner = new Scanner(System.in);
String echoString;
String response;
do {
System.out.println("Enter string to be echoed: ");
echoString = scanner.nextLine();
pw.println(echoString);
if(!echoString.equals("exit")) {
response = br.readLine();
System.out.println(response);
}
} while(!echoString.equals("exit"));
// }catch(SocketTimeoutException e) {
// System.out.println("The Socket has been timed out");
} catch (IOException e) {
System.out.println("Client Error: " + e.getMessage());
}
}
}
server code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
public class EchoMultiThreadServer {
private static Vector<Echoer> clients = new Vector<Echoer>();
public static void main(String [] args) {
try(ServerSocket serverSocket = new ServerSocket(4000)){
while(true) {
Socket socket = serverSocket.accept();
Echoer echoer = new Echoer(socket);
echoer.start();
clients.add(echoer);
}
}catch(IOException e) {
System.out.println("Server Exception"+e.getMessage());
}
}
}
thread code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Echoer extends Thread{
private Socket socket;
public Echoer(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter wr = new PrintWriter(socket.getOutputStream(), true);
while(true) {
String echoString = in.readLine();
System.out.println("Received Client Input: " + echoString);
if(echoString.equals("exit")) {
break;
}
wr.println(echoString);
}
}catch(IOException e) {
System.out.println("Oooops " + e.getMessage());
}finally {
try {
socket.close();
}catch(IOException e) {
// later
}
}
}
}
I can see two problems with your current logic:
At the client side, you are essentially reading user input, then sending to server and getting a (single) response. So the problem here is that you only get one response, while you should take more than one for each user input line: that is the user's input plus the other users' input. Since you don't know when and how many the other users' inputs are going to be, you need to go asynchronous. I mean that you need 2 threads: one for reading user input and the other for reading server input/response (note: we are still at the client side). Since you already have one of the 2 threads, ie the one which runs the main method, then you can use it instead of creating a new one.
At the server side, your Echoer is reading user input but only sending it back to the same client. You need for example a loop to send the client's input to all other clients too.
So what would seem to me a proper logic is:
Client side:
Reading server's responses thread logic:
forever, do:
get server's message.
print server's message to user.
main method:
connect to server.
start a "Reading server's responses thread".
get user input.
while the user's input it not "exit", do:
send user's input to server.
get user input.
disconnect from server.
Server side:
Echoer thread:
forever, do:
read client's message.
for every client, do:
send the message to the client.
main method:
start server socket.
forever, do:
accept incoming connection.
start an Echoer thread for the accepted connection.
There are some missing bits though, such as how to maintain the list of all clients, but for that I can see you are already using a Vector<Echoer> clients at the server side. So just pass that Vector to every Echoer you create, so they can do the broadcasting of each incomming message. Important note here: at the server side, you have more than one threads: the main one and each Echoer, so make sure you synchronize on the Vector while you are modifying it at the main thread and also while broadcasting at the Echoers.
Notes:
I am assuming in all the above logic that there is no particular order in which the clients send their messages. For example if always client A sent first, then client B and so on, and the whole process was repeating, then you wouldn't need to go multithreading at all.
Please take your time. First implement it and then tell me if you encouter any problems.
Edit 1: full sample code.
Client code:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class Client {
//This is the "Reading server's responses thread" I am talking about in the answer.
private static class ReadingRunnable implements Runnable {
private final BufferedReader serverInput;
public ReadingRunnable(final InputStream is) {
serverInput = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
}
#Override
public void run() {
try {
//While the server is not disconnected, we print each line to 'System.out':
for (String line = serverInput.readLine(); line != null; line = serverInput.readLine())
System.out.println(line);
}
catch (final IOException iox) {
iox.printStackTrace(System.out);
}
finally {
System.out.println("Input from server stopped.");
}
}
}
public static void main(final String[] args) {
try {
System.out.print("Connecting... ");
try (final Socket sck = new Socket("localhost", 50505);
final OutputStream os = sck.getOutputStream();
final InputStream is = sck.getInputStream()) {
System.out.println("Connected.");
new Thread(new ReadingRunnable(is)).start();
final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
final Scanner scan = new Scanner(System.in);
for (String userInput = scan.nextLine(); !"exit".equalsIgnoreCase(userInput); userInput = scan.nextLine()) {
bw.write(userInput);
bw.newLine();
bw.flush();
}
}
}
catch (final IOException iox) {
iox.printStackTrace(System.out);
}
finally {
System.out.println("Output from user stopped.");
}
}
}
Server code:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;
public class Server {
private static class Echoer implements Runnable {
private final ArrayList<Echoer> all;
private final BufferedWriter bw;
private final BufferedReader br;
public Echoer(final ArrayList<Echoer> all,
final InputStream is,
final OutputStream os) {
this.all = Objects.requireNonNull(all);
bw = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
}
//Instead of exposing 'bw' via a getter, I just built a helper method to send a message to the Echoer:
public void send(final String msg) throws IOException {
bw.write(msg);
bw.newLine();
bw.flush();
}
#Override
public void run() {
try {
for (String line = br.readLine(); line != null; line = br.readLine()) {
System.out.println(line); //Print the received line at the server.
synchronized (all) { //We are reading from a collection which may be modified at the same time by another (the main) Thread, so we need to synchronize.
//Broadcast the received line:
for (int i = all.size() - 1; i >= 0; --i) {
try {
all.get(i).send(line);
}
catch (final IOException iox) {
all.remove(i); //In case we cannot send to the client, disconnect him, ie remove him from the list in this simple case.
}
}
}
}
}
catch (final IOException iox) {
}
finally {
synchronized (all) {
all.remove(this); //Disconnect him, ie remove him from the list in this simple case.
}
System.out.println("Client disconnected.");
}
}
}
public static void main(final String[] args) throws IOException {
System.out.print("Starting... ");
try (final ServerSocket srv = new ServerSocket(50505)) {
final ArrayList<Echoer> all = new ArrayList<>();
System.out.println("Waiting for clients...");
while (true) {
final Socket sck = srv.accept();
try {
final OutputStream os = sck.getOutputStream();
final InputStream is = sck.getInputStream();
final Echoer e = new Echoer(all, is, os); //Pass all the Echoers at the new one.
synchronized (all) { //We will write to a collection which may be accessed at the same time by another (an Echoer) Thread, so we need to synchronize.
all.add(e); //Update list of Echoers.
}
new Thread(e).start(); //Start serving Echoer.
}
catch (final IOException iox) {
System.out.println("Failed to open streams for a client.");
}
}
}
}
}
my name is Jędrzej and I am new here. I was trying to write a simple chat in java. I am trying to make multithread server so multiple clients can connect to this server. My client works fine, but if I run two clients, they dont see each others responses. Code bellow:`
package serverthread;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerWIthThreads {
public static void main(String[] args){
try{
ServerSocket serverSocket = new ServerSocket(1234);
while(true){
Socket socket = serverSocket.accept();
Runnable r = new ThreadForServer(socket);
Thread t = new Thread(r);
t.start();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
package serverthread;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class ThreadForServer implements Runnable{
private Socket socket;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
public ThreadForServer(Socket i){
socket = i;
}
#Override
public void run(){
try{
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.flush();
while(true){
String message = (String) inputStream.readObject();
outputStream.writeObject(message);
outputStream.flush();
}
}catch(IOException e){
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
`
The way you've implemented this, you're reading a message from one client and then writing it back to the same client.
You'll need to revise your program so that you can write the message to the Socket of the other connected client.
I am trying to create a server listener. It sits back and waits for data coming from the client and performs setting actions due to the nature of the data. But right now, after receiving the first data stream, it goes into a resource hog, the memory usage shoots up and the CPU usage is maxing out a single core.
1 - How can I fix this? How can I make it listen without all the resource hog, as you can see it is a really really small program.
2 - The client itself that sends these data streams, runs once. It starts up, connects to the server, sends the data and quits. While the server is still "on", if I retry running the client again, the server doesn't receive the data.
Server Code:
package mediaserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
ServerSocket ss;
Socket s;
BufferedReader br;
public Main() throws IOException{
ss = new ServerSocket(1111);
s = ss.accept();
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
new Thread(new runner()).start();
}
class runner implements Runnable{
public void run(){
while(true){
try {
String n = br.readLine();
System.out.println(n);
} catch (IOException ex) {
}
finally{
try {
s.close();
ss.close();
} catch (IOException ex) {
}
}
}
}
}
public static void main(String[] args) throws IOException {
new Main();
}
}
Client Code
package mediaserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class test {
public static void main(String [] args) throws UnknownHostException, IOException, InterruptedException{
Socket s = new Socket("127.0.0.1", 1111);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("");
bw.newLine();
bw.flush();
}
}
The server never gets the data on additional run because ss.accept() is only called one time. You need to wrap this in a loop:
s = ss.accept();
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
new Thread(new runner()).start();
The following piece of code is an infinite loop:
while(true) {
try {
String n = br.readLine();
System.out.println(n);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
finally {
...
}
}
Once the client disconnects, the BufferedReader instance will encounter the end-of-file and readLine will return null. The loop then will continue to print null infinitely.
The fix it, check for null:
while(true) {
try {
String n = br.readLine();
if (n == null)
break;
System.out.println(n);
} catch (IOException ex) {
}
finally {
...
}
}
I am trying to write an application using Java that will allow me to transfer files between a server and a client that requests the file. I plan to do it using sockets. My algorithm is somewhat like this:
On Server:
Create the connection between client and server.
Once connected find the file u need to send to client.
Then send the size of file to client.
Then send file broken down in parts.
On Client
After connection is created, ask for the file.
Receive the file size, then accept data till u reach file size.
Stop.
Please correct me if i am wrong somewhere in the algorithm
This isn't really an "algorithm" question; you're designing a (simple) protocol. What you've described sounds reasonable, but it's too vague to implement. You need to be more specific. For example, some things you need to decide:
How does the receiving program know what filename it should save to? Should that be sent through the socket, or should it just ask the user?
How is the file size transmitted?
Is it a character string? If so, how is its length indicated? (With a null terminator? A newline?)
Is it a binary value? If so, how big? (32 bits or 64?) What endianness?
What does "broken down in parts" mean? If you're writing to a TCP socket, you don't need to worry about packet boundaries; TCP takes care of that.
Does the recipient send anything back, like a success or failure indication?
What happens when the whole file has been transmitted?
Should both ends assume that the connection must be closed?
Or can you send multiple files through a single connection? If so, how does the sender indicate that another file will follow?
Also, you're using the terms "client" and "server" backward. Typically the "client" is the machine that initiates a connection to a server, and the "server" is the machine that waits for connections from clients.
You can also add Acknowledgement from server once a particular part of the file is recieved,
similar to what we have in HTTP protocol , that would ensure proper delivery of the file has been received on the server.
Here is the method that I use, it uses the socket's input and output streams to send and receive the files, and when it's done, it will automatically restart the server and reconnect to it from the client.
Server Code:
package app.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Functions
{
private static ServerSocket server;
private static Socket socket;
public static void startServer(int port)
{
try
{
server = new ServerSocket(port);
socket = server.accept();
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void restartServer()
{
new Thread()
{
#Override
public void run()
{
try
{
socket = server.accept();
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();
}
public static void sendFile(String inputFilePath)
{
FileInputStream fis;
BufferedInputStream bis;
OutputStream os;
BufferedOutputStream bos;
try
{
File input = new File(inputFilePath);
fis = new FileInputStream(input);
bis = new BufferedInputStream(fis);
os = socket.getOutputStream();
bos = new BufferedOutputStream(os);
byte[] buffer = new byte[1024];
int data;
while(true)
{
data = bis.read(buffer);
if(data != -1)
{
bos.write(buffer, 0, 1024);
}
else
{
bis.close();
bos.close();
break;
}
}
}
catch (FileNotFoundException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
restartServer();
}
}
Client Code:
package app.client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Functions
{
private static Socket socket;
private static String hostName;
private static int portNumber;
public static void connectToServer(String host, int port)
{
new Thread()
{
#Override
public void run()
{
try
{
hostName = host;
portNumber = port;
socket = new Socket(host, port);
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();
}
private static void reconnectToServer()
{
try
{
socket = new Socket(hostName, portNumber);
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void receiveFile(String outputFilePath)
{
InputStream is;
BufferedInputStream bis;
FileOutputStream fos;
BufferedOutputStream bos;
try
{
File output = new File(outputFilePath);
is = socket.getInputStream();
bis = new BufferedInputStream(is);
fos = new FileOutputStream(output);
bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int data;
while(true)
{
data = bis.read(buffer);
if(data != -1)
{
bos.write(buffer, 0, 1024);
}
else
{
bis.close();
bos.close();
break;
}
}
}
catch (IOException ex)
{
Logger.getLogger(Functions.class.getName()).log(Level.SEVERE, null, ex);
}
reconnectToServer();
}
}
This method works very well, I use it for my server and client file transfer program, all you need to do is enter the Server Host's IP address and choose a port number (I use 8888).
I made a simple chat server and client and the client will send text to the server, and the server will only send it back to the client that sent it to it. I want it to send to all the clients instead of just that one.
Server:
import java.io.IOException;
import java.net.ServerSocket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket s = null;
boolean listening = true;
try {
s = new ServerSocket(5555);
} catch (IOException e) {
e.printStackTrace();
}
while(listening)
new ServerThread(s.accept()).start();
}
}
Thread:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread {
private Socket sock = null;
public ServerThread(Socket socket) {
super("Server Thread.");
this.sock = socket;
}
public void run() {
PrintWriter out = null;
BufferedReader in = null;
try {
System.out.println(sock.getInetAddress() + " has joined.");
out = new PrintWriter(sock.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String input;
while((input = in.readLine()) != null) {
System.out.println(input);
out.println(input);
}
in.close();
out.close();
sock.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Client:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client
{
public static void main(String[] args) throws IOException {
Socket sock = null;
PrintWriter out = null;
BufferedReader in = null;
try {
sock = new Socket("127.0.0.1", 5555);
out = new PrintWriter(sock.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader stdIn = new BufferedReader(new InputStreamReader(
System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println(in.readLine());
}
out.close();
in.close();
sock.close();
}
}
Have your server keep List<ServerThread>. Have a void sendAll(String) method on the Server that can be accessed by the ServerThreads and when they get information, that sendAll() method tells each ServerThread to send out their information.
What you're looking at doing though will require some asynchronous work (and is most certainly not trivial!)
Well, briefly: you're creating those ServerThreads and starting them, but you're not keeping track of them in any way. Imagine if each time you created one, you put it in a HashSet. Then each time a client sent a String, you iterated over the Set and sent the String to each of the clients. A method sendMessage(String) in ServerThread would make this easier, of course.
Change your client to have one thread for reading from the server plus one thread for reading from the keyboard.
Create a function which allows server socket threads to communicate with each other and use synchronization so that only one thread is writing to each outputstream at one time. So in brief, create a list of server threads which is shared by all threads and move your PrintWriter into a field with a getter, so it can be accessed from outside.
glowcoder and Ernest Friedman-Hill seem to be giving good advice, but I wanted to add one thing: have you considered using the Observer pattern and java's default implementation of Observable?
The Server could extend the Observable object, and the ServerThread could implement the Observer interface. As you create new ServerThreads, register them with the Observable using
server.addObserver(serverThread);
The ServerThread will need to know about the Server it is linked to.
Then whenever a client sends in a new message, instead of out.println(userInput) do the following:
synchronized (server) {
server.setChanged();
server.notifyObservers(userInput);
}
You also need to implement ServerThread.update(Observable o, Object update), in which you would get the serverThread's socket's output stream and write ((String) update) to it.
Note that this will use one thread to send messages to all the observers and will block other threads from processing their chats until it has sent to all observers.