I am new to Socket programming in Java and was trying to understand if the below code is not a wrong thing to do. My question is:
Can I have multiple clients on each thread trying to connect to a server instance in the same program and expect the server to read and write data with isolation between clients"
public class Client extends Thread
{
...
void run()
{
Socket socket = new Socket("localhost", 1234);
doIO(socket);
}
}
public class Server extends Thread
{
...
void run()
{
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
Now can I have multiple Client instances on different threads trying to connect on the same port of the current machine?
For example,
Server s = new Server("localhost", 1234);
s.start();
Client[] c = new Client[10];
for (int i = 0; i < c.length; ++i)
{
c.start();
}
Yes, however only one client will be able to connect per thread execution as written.
You can just put your server run() inside a while true loop to let multiple clients connect.
Depending on the executor, they will execute either in series or parallel.
public class Server extends Thread
{
...
void run()
{
while(true){
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
}
As long as you only have one object trying to bind the port for listening, then there's no problem with multiple clients connecting.
In this example, your Server accepts and handles one client connection at a time. You can have as many Clients as you want attempting to connect, but only one at a time will be handled.
It is not apparent whether your executor logic is multithreaded, since you didn't provide the implementation. If the executor delegates to a threadpool or something like that, you would need to make sure that your ClientWorker is thread-safe, as you will have multiple instances executing in parallel.
I am of course assuming that your Client is thread-safe as well, since your question is only concerning the Server.
Yes, it doesn't matter whether your clients are local or remote. The important thing in your example is that ClientWorker is thread-safe, as your server will have multiple instances of that class (one for each client connection).
So. To begin:
You can accept more clients with one serversocket, because you accept only one in the run-method. You have just to call accept() a second time.
Then, you in your for loop: first you have to create each time a new Client object. Then you can call c[i].start(); and not c.start().
Now can I have multiple Client
instances on different threads trying
to connect on the same port of the
current machine?
Yes you can. Just create new Threads and run them. This should work perfectly.
expect the server to read and write
data with isolation between clients
You can use your experience of the basic IO techniques like with file-io:
OutputStream os = socket.getOutputStream();
PrintStream pw = new PrintStream(os, true); // Or PrintWriter, I don't know what the best one is.
pw.println("Hello, other side of the connection!");
And for reading use a BufferedReader.
You can try something on these lines
public class MultiThreadServer extends Application {
// Text area for displaying contents
private TextArea ta = new TextArea();
// Number a client
private int clientNo = 0;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a scene and place it in the stage
Scene scene = new Scene(new ScrollPane(ta), 450, 200);
primaryStage.setTitle("MultiThreadServer"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
new Thread( () -> {
try {
// Create a server socket
ServerSocket serverSocket = new ServerSocket(8000);
ta.appendText("MultiThreadServer started at "
+ new Date() + '\n');
while (true) {
// Listen for a new connection request
Socket socket = serverSocket.accept();
// Increment clientNo
clientNo++;
Platform.runLater( () -> {
// Display the client number
ta.appendText("Starting thread for client " + clientNo +
" at " + new Date() + '\n');
// Find the client's host name, and IP address
InetAddress inetAddress = socket.getInetAddress();
ta.appendText("Client " + clientNo + "'s host name is "
+ inetAddress.getHostName() + "\n");
ta.appendText("Client " + clientNo + "'s IP Address is "
+ inetAddress.getHostAddress() + "\n");
});
// Create and start a new thread for the connection
new Thread(new HandleAClient(socket)).start();
}
}
catch(IOException ex) {
System.err.println(ex);
}
}).start();
}
// Define the thread class for handling new connection
class HandleAClient implements Runnable {
private Socket socket; // A connected socket
/** Construct a thread */
public HandleAClient(Socket socket) {
this.socket = socket;
}
/** Run a thread */
public void run() {
try {
// Create data input and output streams
DataInputStream inputFromClient = new DataInputStream(
socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(
socket.getOutputStream());
// Continuously serve the client
while (true) {
// Receive radius from the client
double radius = inputFromClient.readDouble();
// Compute area
double area = radius * radius * Math.PI;
// Send area back to the client
outputToClient.writeDouble(area);
Platform.runLater(() -> {
ta.appendText("radius received from client: " +
radius + '\n');
ta.appendText("Area found: " + area + '\n');
});
}
}
catch(IOException e) {
ex.printStackTrace();
}
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Related
I am creating a simple java program that creates two threads when it starts, each of these thread creates a server that listen to different port(ie port 5500, 5100), those servers each have clients, now i want the servers to be able to pass information from their client to each other. How do i do that. this is the code i have for the servers
class SocketSeverBrooker extends Thread{
int portNumber = 5500;
ServerSocket serverSocket = null;
int clientID = 10000;
public void run(){
try {
serverSocket = new ServerSocket(portNumber);
while(true){
try{
// i am accepting acconection from a client
Socket clientsocket = serverSocket.accept();
new Thread(new BrokerRunnable(clientsocket)).start();
System.out.println("a broker has connected with id "+ clientID);
clientID++;
}catch(IOException e){
System.out.println("client could not connect");
}
}
}catch (IOException e){
System.out.println("could not create a connection");
}
}
}
class BrokerRunnable implements Runnable{
protected Socket clientSocket;
public BrokerRunnable(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
// create two way communication
// this is used to get input from the connected client clientSocket.getInputStream()
// new BufferedReader();
try{
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);// write the sever
String arg1;
arg1 = in.readLine();
System.out.println( arg1);
Scanner scanner = new Scanner(System.in);
String msgToBrokker = scanner.nextLine();
out.println(msgToBrokker);
}catch(IOException e){
System.out.println("could not read");
}
}
}
I am unable to ask a question using a comment. Hence writing here. Sorry.
What i understood from the question, Please correct me if this is not the case.
We have multiple servers (S) and each may have multiple clients (C) too.
S1 -> S1C1, S1C2, ...., S1Cn
S2 -> S2C1, S2C2, ...., S2Cn
......
Sm -> SmC1, SmC2, ...., SmCn
Servers to share information with other servers that can be passed to clients.
If above understanding is correct, then you should have a common object (like a list, map) which can be shared by all the Servers. This object will store the information from all the servers. You will need to put a logic how will you which information to read by a server (for ex. S1 shouldn't read the information added by itself).
Hope this helps.
I am trying to improve the speed at which the sockets transfer information but i am unsure how to do so. the pourpose of the code is to transfer a number, the date, and a short xml which is being sent in the form of a string.
this is the server code
import java.net.*;
import java.io.*;
public class SSocket extends Thread
{
private ServerSocket serverSocket;
public SSocket(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(100000);
}
public void run()
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
while(true)
{
try
{
Socket server = serverSocket.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
int cor=in.readInt();
int i=0;
String transaccion = in.readUTF();
String fecha = in.readUTF();
System.out.println(cor);
System.out.println(transaccion);
System.out.println(fecha);
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
if(transaccion!=null && fecha != null && cor>0){
out.writeInt(cor);
}
else {
out.writeInt(-1);
}
if (i==100){
out.flush();
i=0;
}
i++;
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = 1337;
try
{
Thread t = new SSocket(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
the code for the client is
import java.net.*;
import java.io.*;
public class ClientSocket
{
public static void send(int correl, String transaccion, String fecha)
{
String serverName = "localhost";
int port = 1337;
try
{
Socket client = new Socket(serverName, port);
int i=0;
OutputStream outToServer = client.getOutputStream();
DataOutputStream out =
new DataOutputStream(outToServer);
out.writeInt(correl);
out.writeUTF(transaccion);
out.writeUTF(fecha);
InputStream inFromServer = client.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
int corin=in.readInt();
if(corin>0){
Envio.updater(corin);
}
else {
}
if (i==100){
out.flush();
i=0;
}
i++;
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
i have done some reading on the mater and it seems that posible solutions are to use either a buffer or swich to a datagram. however my experience on working with sockets is rather limited and i am unsure which would be best to use for this situation or if there is another option i havent yet considered. this code will be moving many transactions and i wish to do it in as short time as posible.
thanks in advance
ps. sorry for my bad english it is not my first language
Datagrams imply UDP, which is an unreliable delivery protocol so you're not guaranteed to get all content. That's probably not what you want; I'd stay with plain Sockets (which use TCP, which has reliable delivery).
Will the same client be calling send() repeatedly and connecting to the same server each time? That is, will there be many messages going across a single connection, or will each message be to a different server, with only a single message (or only a few) going to each of the many servers? If there's just one server that a client is going to connect to and if a given client is going to send lots of messages, you should keep the Socket open between send() calls; setting up and tearing down Sockets is expensive, so you're paying a high price for making a new connection each time.
Also, your server appears to only be able to handle a single connection at a time: you accept a connection, read from it, and then close it and accept a new one. So to make this work for more than one client, you'll need to separate the logic for accepting connections onto a different thread from the logic that reads data. If you'll only have a few clients at a time, you can just start a new thread to read from each socket as you create it for a new client; if you'll have lots of clients (thousands), you'll probably need to look at NIO for its ability to service multiple sockets from a single thread. But I suspect you're a long way from having that problem, if you ever do, so I'd just spawn a new thread for each socket.
i'm trying create "multi-client -- single server" connection.
My client(s) opens connection and in the server side I've create
Client clt = new Client("127.0.0.1", 9000);
clt.openConn();
...
public Client(String serverAddress, int serverPort) {
this.serverAddress = serverAddress;
this.serverPort = serverPort;
}
try {
this.clientSocket = new Socket(this.serverAddress, this.serverPort);
this.clientSocket.setKeepAlive(true);
this.clientSocket.setSoTimeout(0);
oos = new DataOutputStream(this.clientSocket.getOutputStream());
ois = new DataInputStream(this.clientSocket.getInputStream());...}
...
on the server side i've created ListArray of ServerSocket's each onf them I wrapped on the Thread.
ServerSocket serverSocket = null ;
Socket clientSocket;
boolean listening = true;
ArrayList threadList = new ArrayList();
Iterator itSrvThr;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + port + ".");
System.exit(-1);
}
while (listening) {
clientSocket = serverSocket.accept();
ServerThread srvThread = new ServerThread(clientSocket);
srvThread.start();
`...`
}
where
ServerThread extends Thread
{...
public void run() {
this.ois = new DataInputStream(socket.getInputStream());
this.oos = new DataOutputStream(socket.getOutputStream());
}
}
my program send and receive objects(i've called them "Datagramm") which are some kind of wrappers for file and strings (let us say it is some language for client-server)
And now about problem which I have. I must to make verification every time when need to test for "alive" socket from server side...
i'm trying to make this verification when appears new element in the ArrayList in that moment but it brings me problem with "Datagramm's" sending
itSrvThr = threadList.iterator();
while (itSrvThr.hasNext()) {
ServerThread st = (ServerThread) itSrvThr.next();
boolean stoppedSocket = st.getStopped();
if (stoppedSocket) {
st.stop();
itSrvThr.remove();
}else {??? resolution???}
stoppedSocket - it's a value which significate programly turned off socket from client site.
Honestly, i'm working with sockets and threads only a couple weeks, that is why every help and critics will be acceptable.
...
Thank for answer but I have problems with codding of heartbeats. First of them where exactly the place of heartbeat must be placed on the server side.
I suggest you send a heartbeat message from the client and/or the server whenever you haven't sent a message for a while (seconds) The other end can timeout when you haven't recieved anything for some multiple of this time.
If you have a protocol like {message length} {message} I use a message-length=0 as a heartbeat.
I'm trying to test a scenario where one server accepts connections(one each time) from one client, using always the same ports (on the server and on the client side).
The purpose is to have 1 client application sending little pieces of data at a rate bigger than 100/min. The well obvious solution would be to have an always connected link between the client and the server, but this is production stuff, and that would require bigger changes in the code that is already implemented. With the solution we have implemented today, we always have +-1K of connections in TIME_WAIT, and I want to get rid of them.
I have implemented a simple tester, and the code is:
public class Server {
public static void main(String[] args) {
ServerSocket ssock = null;
try {
ssock = new ServerSocket();
ssock.bind(new InetSocketAddress(Common.SERVER_PORT));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
while(true){
try{
Socket cSock = ssock.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(cSock.getInputStream()));
reader.readLine();
PrintWriter writer = new PrintWriter(cSock.getOutputStream());
writer.println(Common.SERVER_SEND);
writer.flush();
reader.close();
writer.close();
cSock.close();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
}
}
}
}
public class Client {
public static void main(String[] args) throws Exception {
InetSocketAddress cliAddr = new InetSocketAddress(
InetAddress.getByName(args[0]),
Common.CLIENT_PORT);
InetSocketAddress srvAddr = new InetSocketAddress(
InetAddress.getByName(args[1]),
Common.SERVER_PORT);
for(int j=1;j<=50;j++){
Socket sock = null;
try{
sock = new Socket();
sock.setReuseAddress(true);
sock.bind(cliAddr);
sock.connect(srvAddr);
PrintWriter writer =
new PrintWriter(
sock.getOutputStream());
writer.println(Common.CLIENT_SEND);
writer.flush();
BufferedReader reader =
new BufferedReader(
new InputStreamReader(
sock.getInputStream()));
reader.readLine();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(-1);
}finally{
if(sock!=null) sock.close();
System.out.println("Done " + j);
}
}
}
}
public class Common {
public static final int SERVER_PORT = 9009;
public static final int CLIENT_PORT = 9010;
public static final String CLIENT_SEND = "Message";
public static final String SERVER_SEND = "OK";
}
When executing the client and server, on windows hosts, in one client execution I always get
java.net.ConnectException: Connection timed out
When executing the client and the server in linux hosts, on some client executions I get a
java.net.NoRouteToHostException: Cannot assign requested address
I've been killing my head over this behavior. Can someone please tell me if it is possible to do what I want, and what I am doing wrong?
If you want to get rid of the TIME_WAIT state, don't be the peer that receives the close. Be the peer that initiates the close. In this case, close the connection immediately after reading the response, and have the server cycle around looking for another request so that it reads the EOF rather than just closing the connection immediately after sending the response. However this will only make the problem worse, as all the TIME_WAIT states will accumulate at the server rather than at the client. On the other hand, the server is now structured to accept multiple requests per connection, so then all you have to do is adapt the clients to use a connection pool and all your problems are solved.
i have the follwoing code of proxy server. IS if the right approach? Will this be able to handel load/trafffic if deployed comerially??
package proxyserver;
import com.sun.corba.se.spi.activation.Server;
import java.net.* ;
import java.io.* ;
import java.lang.* ;
import java.util.* ;
/**
*
* #author user
*/
public class Main {
/**
* #param args the command line arguments
*/
// Variable to track if an error occurred
boolean errorOccurred = false;
//Variables for the host and port parameters
public static void main(String[] args) {
// TODO code application logic here
int localPort = -1;
int remotePort = -1;
String remoteHost = "www.youtube.com";
System.out.print("dwdsw");
Integer parseLocalPort = new Integer(555);
Integer parseRemotePort = new Integer(80);
localPort =80 ;
remotePort = 80;
//Create a listening socket at proxy
ServerSocket server = null;
try
{
server = new ServerSocket(localPort);
}
catch(IOException e)
{
System.err.println("Error: " + e.getMessage());
System.exit(-1);
}
//Loop to listen for incoming connection,
//and accept if there is one
Socket incoming = null;
Socket outgoing = null;
while(true)
{
try
{
// Create the 2 sockets to transmit incoming
// and outgoing traffic of proxy server
incoming = server.accept();
outgoing = new Socket(remoteHost, remotePort);
// Create the 2 threads for the incoming
// and outgoing traffic of proxy server
ProxyThread thread1 = new ProxyThread(incoming, outgoing);
thread1.start();
ProxyThread thread2 = new ProxyThread(outgoing, incoming);
thread2.start();
}
catch (UnknownHostException e)
{
System.err.println("Error: Unknown Host " + remoteHost);
System.exit(-1);
}
catch(IOException e)
{
//continue
System.exit(-2);;
}
}
}
}
now proxy classs
package proxyserver;
/**
*
* #author user
*/
import java.net.* ;
import java.io.* ;
import java.lang.* ;
import java.util.* ;
class ProxyThread extends Thread
{
Socket incoming, outgoing;
ProxyThread(Socket in, Socket out)
{
incoming = in;
outgoing = out;
}
// Overwritten run() method of thread,
// does the data transfers
public void run()
{
byte[] buffer = new byte[5000];
int numberRead = 0;
OutputStream toClient;
InputStream fromClient;
try{
toClient = outgoing.getOutputStream();
fromClient = incoming.getInputStream();
while(true)
{
numberRead = fromClient.read(buffer, 0, 50);
if(numberRead == -1)
{
incoming.close();
outgoing.close();
}
String st = new String(buffer,"US-ASCII");
System.out.println("\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\nXXXXXXXXXXXXXXXX\n\n" + st);
toClient.write(buffer, 0, numberRead);
}
}
catch(IOException e)
{
}
catch(ArrayIndexOutOfBoundsException e)
{
}
}
}
[ OK ... enough teasing :-) ]
It looks like it should work, though:
The stuff that you print to System.err in the Proxy class may be mangled. (As I said before, you cannot just assume that every web page is encoded in ASCII!!)
You should probably be reading much more than 50 bytes at a time .... especially if you want high throughput.
Your main class probably should be using a thread pool rather than creating and throwing away threads. And you probably should put an upper bound on the number of threads you want to allow at any given time.
You probably need to do something about servers that take a long time to deliver their responses, etcetera.
Finally, in response to this:
Will this be able to handle the
load/traffic if it is deployed commercially??
It is impossible to say how much load you could pump through this program. For a start, it will depend on your processor and network interface hardware.
It looks about right in principle but you should take a look at an open source version like TCP Proxy for pointers on maximizing throughput, increasing resilience, etc.