I am trying to establish a communication between a server (NewServer class) and a client (NewClient class), accepting two Client communications. I know how to do it with one client but not multiple client connections.
Do I have to create 2 readers in the Client class?
Can I do this in a recursive way?
Server Class:
import java.net.*;
import java.io.*;
public class NewServer
{
//Create Server Socket and a Client Socket for each Client.
static ServerSocket server;
static Socket client1;
static Socket client2;
//Create OutputStreams to send information to each Client.
static DataOutputStream client1writer;
static DataOutputStream client2writer;
static final int PORT = 9999;
//Main Method
public static void main(String[]args)
{
//Try-Catch Block for Socket Errors.
try
{
//Create the Server Socket as a Host.
server = new ServerSocket(PORT);
//Connect Client 1 – First run of the Client class.
client1 = server.accept();
client1writer = new
DataOutputStream(client1.getOutputStream());
//Connect Client 2 – Second run of the Client class.
client2 = server.accept();
client2writer = new
DataOutputStream(client2.getOutputStream());
//Assign each Client an ID number – this is how the Client will know
// which individual Client it’s representing in RunTime.
int ID1 = 8675309;
int ID2 = 8675308;
//Tell both Clients which one they are representing.
client1writer.writeInt(ID1);
client2writer.writeInt(ID2);
//Close all Sockets when finished.
client1.close();
client2.close();
server.close();
}
catch (IOException IOex)
{
System.out.println("Server Error.");
}
}
}
Client class:
import java.net.*;
import java.io.*;
public class NewClient {
static Socket client = null;
static final int PORT = 9999;
static final String IP = "localhost";
public static void main(String[] args) throws IOException {
int id1;
int id2;
try{
client = new Socket(IP,PORT);
System.out.println("Connection successful!");
reader = new DataInputStream(client.getInputStream());
id1 = reader.readInt();
id2 = reader.readInt();
System.out.println("The id of the user is " + id);
//Closing everything
client.close();
reader.close();
}catch(IOException error) {
System.err.println("Server error.");
}
}
}
You can achieve it by starting a separate thread (also known as Plain threads for every new client connection and then call server.accept() which runs in a loop. It is useful as an learning example but will not help you achieve what you need as you loose control of threads.
Second way is to use Executor Service which provides better management control over the above solution.
Related
I am writing a web server/client. When communicating over localhost, things are fine. But when communicating using my public IP address, an exception is thrown. Here is a minimal working example:
import java.io.*;
import java.text.*;
import java.util.*;
import java.net.*;
public class Server
{
public static void main(String[] args) throws IOException
{
int port = 80;
// server is listening on port
ServerSocket ss = new ServerSocket(port);
// running infinite loop for getting
// client request
while (true)
{
Socket s = null;
try
{
// socket object to receive incoming client requests
s = ss.accept();
System.out.println("A new client is connected : " + s);
// obtaining input and out streams
ObjectOutputStream odos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream odis = new ObjectInputStream(s.getInputStream());
Info info = new Info();
info.color = 1;
odos.writeObject(info);
while(true){
info = (Info)odis.readObject();
if(info.exit){
break;
}
}
// closing resources
odis.close();
odos.close();
}
catch (Exception e){
s.close();
e.printStackTrace();
}
}
}
}
And the Client:
import java.util.*;
import java.net.*;
import java.io.*;
import java.net.InetAddress;
public class Client
{
public static void main(String[] args) {
if(args.length>0){
ip_name = args[0];
}
if(args.length>1){
port = Integer.parseInt(args[1]);
}
network();
}
private static String ip_name = "localhost";
private static int port = 80;
private static void network(){
try
{
System.out.println("Connecting to network");
InetAddress ip = InetAddress.getByName(ip_name);
// establish the connection with server port
Socket s = new Socket(ip, port);
System.out.println("Connected");
// obtaining input and out streams
ObjectOutputStream odos = new ObjectOutputStream(s.getOutputStream());
InputStream i = s.getInputStream();
ObjectInputStream odis = new ObjectInputStream(i);
// get what color we are
int color = ((Info)odis.readObject()).color;
System.out.println(color);
//say we are done
Info info = new Info();
info.exit = true;
odos.writeObject(info);
System.out.println("Shutting down");
}catch(Exception e){
e.printStackTrace();
}
}
}
When using localhost, the client prints out, as expected:
Connecting to network
Connected
1
Shutting down
but when I replace localhost with my public IP:
Connecting to network
Connected
java.io.StreamCorruptedException: invalid stream header: 48545450
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at Client.network(Client.java:36)
at Client.main(Client.java:14)
48545450 is hex for "HTTP", but beyond that I can't tell what the problem is. Any ideas?
When I tried running your code I got error "Info is non-serilizable". I have modified your Info class as follows.
import java.io.Serializable;
public class Info implements Serializable {
public int color;
public boolean exit;
}
You need to implement Serializable If you are sending class data. Using this you can persist object info over a network.
Guys I want to convert my server implementation into multi thread so that it can handle multiple requests. Basically the server is connected with an android application and it is recieving an image from android application. I want to add a thread so that it can handle multiple requests and the thread should start when the request is recieved. Kindly help me out.
This is the Server Code.
public static void main(String[] args) throws UnknownHostException, IOException, MatlabInvocationException, MatlabConnectionException {
while (true) {
try {
serverSocket = new ServerSocket(4001); // Server socket
} catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
System.out.println("Server started. Listening to the port 4001");
clientSocket = serverSocket.accept();
DataInputStream inputFromClient = new DataInputStream(clientSocket.getInputStream());
int count = inputFromClient.readInt();
int available = inputFromClient.available();
System.out.println("Length of Image in Bytes:" + count);
System.out.println("available:" + available);
image = new byte[count];
inputFromClient.readFully(image);
System.out.println(image.length);
System.out.println(image);
final BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(image));
ImageIO.write(bufferedImage, "jpg", new File("image.jpg"));
System.out.println("Image has been wriiten in the directory.");
MatlabProxyFactory mpf = new MatlabProxyFactory();
MatlabProxy proxy = mpf.getProxy();
proxy.eval("conclusion=DetectColorL");
Object[] obj = proxy.returningEval("conclusion", 1);
String Message = obj[0].toString();
DataOutputStream outTo = new DataOutputStream(clientSocket.getOutputStream());
outTo.writeUTF(Message.toString());
System.out.println(Message);
proxy.disconnect();
serverSocket.close();
To make it multithreaded you want to be able to have multiple clients connected at the same time, to handle multiple requests instead of one at a time.
To do so, your server will have to permanently accept new clients.
public static void main(String[] args) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(4001); // Server socket
System.out.println("Server started. Listening to the port 4001");
while (true) {
// Always accept new clients
Socket clientSocket = serverSocket.accept();
new RequestHandlingClass(clientSocket).start(); // Make a new thread and call it's run procedure
}
} catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
}
Now our server accepts multiple clients we have to implement the RequestHandlingClass class. You want that class to listen for client requests and handle them.
public class RequestHandlingClass() extends Thread {
Socket clientSocket;
DataInputStream inputFromClient;
RequestHandlingClass(Socket clientSocket) {
this.clientSocket = clientSocket;
this.inputFromClient = new DataInputStream(clientSocket.getInputStream());
// ...
}
public void run() {
// Handle client requests
}
}
Based on your question I suppose you want to execute the "image handling" code in the run method.
I am currently trying to take an ArrayList and fill it with sockets using .add, when the socket is passed into the constructor. When i run the debug, it looks like there is only ever 1 socket filling the ArrayList, and no more, even though I've opened like 6 client threads.
Server class
public static void main(String[] args) throws IOException
{
final int PORT = 8888;
ServerSocket server = new ServerSocket(PORT);
System.out.println("Waiting...");
while(true)
{
Socket s = server.accept();
System.out.println("Client connected");
Service service = new Service(s);
Thread t = new Thread(service);
t.start();
}
Service class
public class Service implements Runnable
{
private Socket s;
private Scanner in;
private PrintWriter out;
private ArrayList<Socket> sockets = new ArrayList<Socket>();
public Service(Socket aSocket)
{
s = aSocket;
sockets.add(s);
}
It's because you create a new Service every loop => you will have 6 Service objects with one arrayList in each containing each objects socket. If you want your arrayList to contain all clients / sockets, you will have to have this list in your server class. Also it's rarely a good idea for your clients to know about all other clients.
I also suggest putting in a Thread.sleep(100) in your main method (server), otherwise it will take up a lot of your precessing power.
public static void main(String[] args) throws IOException
{
final int PORT = 8888;
ServerSocket server = new ServerSocket(PORT);
System.out.println("Waiting...");
private ArrayList<Socket> sockets = new ArrayList<Socket>();
while(true)
{
Thread.sleep(100);
Socket s = server.accept();
System.out.println("Client connected");
Service service = new Service(s);
Thread t = new Thread(service);
t.start();
sockets.add(s);
}
basically what i want to do is develop a chat program(something between an instant messenger and IRC) to improve my java skills.
But I ran into 1 big problem so far: I have no idea how to set up streams properly if there is more than one client. 1:1 chat between the client and the server works easily, but I just don't know what todo so more than 1 client can be with the server in the same chat.
This is what I got, but I doubt its going to be very helpful, since it is just 1 permanent stream to and from the server.
private void connect() throws IOException {
showMessage("Trying to connect \n");
connection = new Socket(InetAddress.getByName(serverIP),27499);
showMessage("connected to "+connection.getInetAddress().getHostName());
}
private void streams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
showMessage("\n streams working");
}
To read from multiple streams in one program, you're going to have to use multithreading. Because reading from streams is synchronous, you'll need to read from one stream for each thread. See the java tutorial on threads for more info on multithreading.
I've done this several times with ServerSocket(int port) and Socket ServerSocket.accept(). This can be pretty simple by having it listen to the one port you want your chat server client listening on. The main thread will block waiting for the next client to connect, then return the Socket object to that specific client. Usually you'll want to put them in a list to generically handle n-number of clients.
And, yes, you will probably want to make sure each Socket is in a different thread, but that's entirely up to you as the programmer.
Remember, there is no need to re-direct to another port on the server, by virtue of the client using a different source port, the unique 5-tuple (SrcIP, SrcPort, DstIP, DstPort, TCP/UDP/other IP protocol) will allow the one server port to be re-used. Hence why we all use stackoverflow.com port 80.
Happy Coding.
Made something like that a few months back. basically I used a separate ServerSocket and Thread per client server side. When client connects you register that port's input and output streams to a fixed pool and block until input is sent. then you copy the input to each of the other clients and send. here is a basic program run from command line:
Server code:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class ChatServer {
static int PORT_NUMBER = 2012;
public static void main(String[] args) throws IOException {
while (true) {
try (ServerSocket ss = new ServerSocket(PORT_NUMBER)) {
System.out.println("Server waiting #" + ss.getInetAddress());
Socket s = ss.accept();
System.out.println("connection from:" + s.getInetAddress());
new Worker(s).start();
}
}
}
static class Worker extends Thread {
final static ArrayList<PrintStream> os = new ArrayList(10);
Socket clientSocket;
BufferedReader fromClient;
public Worker(Socket clientSocket) throws IOException {
this.clientSocket = clientSocket;
PrintStream toClient=new PrintStream(new BufferedOutputStream(this.clientSocket.getOutputStream()));
toClient.println("connected to server");
os.add(toClient);
fromClient = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
}
#Override
public void run() {
while (true) {
try {
String message = fromClient.readLine();
synchronized (os) {
for (PrintStream toClient : os) {
toClient.println(message);
toClient.flush();
}
}
} catch (IOException ex) {
//user discnnected
try {
clientSocket.close();
} catch (IOException ex1) {
}
}
}
}
}
}
Client code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
final BufferedReader fromUser = new BufferedReader(new InputStreamReader(System.in));
PrintStream toUser = System.out;
BufferedReader fromServer;
final PrintStream toServer;
Socket s = null;
System.out.println("Server IP Address?");
String host;
String port = "";
host = fromUser.readLine();
System.out.println("Server Port Number?");
port = fromUser.readLine();
s = new Socket(host, Integer.valueOf(port));
int read;
char[] buffer = new char[1024];
fromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
toServer = new PrintStream(s.getOutputStream());
new Thread() {
#Override
public void run() {
while (true) {
try {
toServer.println(">>>" + fromUser.readLine());
toServer.flush();
} catch (IOException ex) {
System.err.println(ex);
}
}
}
}.start();
while (true) {
while ((read = fromServer.read(buffer)) != -1) {
toUser.print(String.valueOf(buffer, 0, read));
}
toUser.flush();
}
}
}
I have a question, I'm currently working on a little project of mine and stumbled upon a dead end. I have a Java Server :
import java.io.*;
import java.net.*;
class TCPServer
{
public static void main(String argv[]) throws Exception
{
ServerSocket welcomeSocket = new ServerSocket(3443);
Socket clientSocket =null;
ClientHandler ch;
while(true)
{
try{
clientSocket = welcomeSocket.accept();
System.out.println("Client connected on port :"+clientSocket.getPort());
ch = new ClientHandler (clientSocket);
Thread t = new Thread(ch);
t.start();
}catch (Exception e){
System.out.println("SERVER CRASH");
}
}
}
}
Then the client connects through the port 3443, a new thread is created with ClientHandler. Now is the problem, in the client side the socket used to connect is still on port 3443, but on the server side the thread is on an arbitrary port, let's say 5433, so the server can communicate with the thread but not the client, because it has no knowledge of what port the thread is using... I'm a bit confused with all this, does the client class is only needed to make the initial connection, then all the communication is done through the ClientHandler class, if so should i also instantiate an object of ClientHandler in the client class?
Here's my client class :
import java.io.*;
import java.net.*;
class TCPClient
{
static Socket clientSocket = null;
public static void main(String argv[]) throws Exception
{
BufferedReader k = new BufferedReader(new InputStreamReader(System.in));
BufferedReader ine = null;
DataOutputStream oute = null;
try{
clientSocket = new Socket("localhost", 3443);
oute = new DataOutputStream(clientSocket.getOutputStream());
ine = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (UnknownHostException e) {
System.out.println("Unknown host");
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
try{
//send
oute.writeBytes(k.readLine());
//recieve
String line = ine.readLine();
System.out.println("Text received: " + line);
} catch (IOException e){
System.out.println("Read failed");
System.exit(1);
}
}
}
The problem is the socket created in client is still connected to Port 3443, and the server is listening to this port, so I won't recieve anything from the server (infinite loop). The clientHandler is on another port. Am i doing it wrong?
You’re calling accept() twice. Call it only once and store the resulting Socket in a variable that you can then hand in to new ClientHandler().
Oh, also, the Socket knows both sides of the communication so it won’t be confused by whatever port the client uses.