Multiple Clients Access the Server Concurrently

How do multiple clients connect simultaneously to one port, say 80, on a server?

First off, a "port" is just a number. All a "connection to a port" really represents is a packet which has that number specified in its "destination port" header field.

Now, there are two answers to your question, one for stateful protocols and one for stateless protocols.

For a stateless protocol (ie UDP), there is no problem because "connections" don't exist - multiple people can send packets to the same port, and their packets will arrive in whatever sequence. Nobody is ever in the "connected" state.

For a stateful protocol (like TCP), a connection is identified by a 4-tuple consisting of source and destination ports and source and destination IP addresses. So, if two different machines connect to the same port on a third machine, there are two distinct connections because the source IPs differ. If the same machine (or two behind NAT or otherwise sharing the same IP address) connects twice to a single remote end, the connections are differentiated by source port (which is generally a random high-numbered port).

Simply, if I connect to the same web server twice from my client, the two connections will have different source ports from my perspective and destination ports from the web server's. So there is no ambiguity, even though both connections have the same source and destination IP addresses.

Ports are a way to multiplex IP addresses so that different applications can listen on the same IP address/protocol pair. Unless an application defines its own higher-level protocol, there is no way to multiplex a port. If two connections using the same protocol simultaneously have identical source and destination IPs and identical source and destination ports, they must be the same connection.

How ServerSocket deal with multiple connection from clients at the same time?

what happens if 2 clients try to connect AT THE SAME TIME

It is impossible for 2 clients to connect at exactly the same time: networking infrastructure guarantees it. Two requests happening at the exact same time is called a collision (wikipedia), and the network handles it in some way: it can be through detection or through avoidance.

How the server process multiple messages from one client? I mean, does it process in order?

Yes. The Socket class API uses the TCP/IP protocol, which includes sequence numbers in every segment, and re-orders segments so that they are processed in the order they are sent, which may be different from the order they are received.

If you used DatagramSocket instead, that would use UDP, which does not guarantee ordering.

Same question above BUT with multiple messages from multiple clients?

There are no guarantees of the relative ordering of segments sent from multiple sources.

Serving files concurrently to multiple clients in node

After thinking about your issue, I'm confused as to why you believe there's an issue. CreateReadStream is asynchronous. Here is in example that complicates the code a little bit in order to demonstrate that using CreateReadStream we can indeed service multiple connections at a time.

/*jshint node:true*/
var http = require('http');
var fs = require('fs');
var activeRequests = 0;
var launchFiveRequests = 5;

http.createServer(function (req, res) {

activeRequests++;

console.log('Request received');

var readStream = fs.createReadStream('play.js', {'bufferSize': 1024});

readStream.setEncoding('utf8');

readStream.on('data', function (data) {
console.log(activeRequests);
res.write(data);
});

readStream.on('end', function () {
res.end();
console.log('end');
activeRequests--;
});

}).listen(8080);

var options = {
hostname: 'localhost',
port: 8080,
path: '/'
};

while(launchTenRequests--) {
http.get(options, function(res) {
console.log('response received');
});
}

Serving up a sufficiently large file, and you should see that all 5 requests are live at once, and all end up ending relatively simultaneously.

PHP multiple clients accessing same file

You could use flock() to get an exclusive lock on a file, see http://php.net/manual/en/function.flock.php

$fp = fopen("/tmp/lock.txt", "r+");

if (flock($fp, LOCK_EX)) {
$datei = fopen("/countlog.txt","r");
$count = fgets($datei,1000);

$count=$count + 1 ;
echo "$count" ;
echo " hits" ;
echo "\n" ;

ftruncate($fp, 0);
fwrite($fp, $count);
fflush($fp);
flock($fp, LOCK_UN);
} else {
echo "Could not lock file!";
}

fclose($fp);

Maybe you should build a loop that waits for a successfull lock using usleep() to avoid active waiting: http://php.net/manual/en/function.usleep.php

Java - Server serves multiple clients at the same time

You do not have to overwrite start(), you must overwrite run()

private class ClientThread extends Thread{
Socket s;
Scanner sc;
PrintWriter pw;

ClientThread(Socket s){
this.s = s;
}

@Override
public void run() {
try{
String in,out;

sc = new Scanner(s.getInputStream());
pw = new PrintWriter(s.getOutputStream(), true);
int i=0;
do{
in = sc.nextLine();
System.out.println("In: " + in);
int tmp = Integer.parseInt(in)+1;
out = Integer.toString(tmp);
pw.println(out);
i++;
}while(i<10);
}catch(Exception e){}
}
}

Server thread:

@Override
public void run(){
try{
ServerSocket ss = new ServerSocket(port);
while(true){
Socket cl = ss.accept();
new ClientThread(cl).start();
}
}catch(Exception e){}
}

Java Server with Multiclient communication.

Here I am sharing you a nice Chat Program having one server that is communicating with multiple clients using TCP protocol as per your requirement.

Program contains:

  • Each client is informed wherever a new client is added along with their name and position.
  • It also checks for existing names. Program doesn't allow multiple clients using same name.

Use this program as initial starter for your game. Please let me know if you want to add new functionality in the program.

Here is the code (see code comments for more clarification):

Note: replace host name in LiveChatClient.java file before running this program at port no 1234

Steps to run the program:

  • first run LiveChatServer only for single time
  • then run LiveChatClient for multiple clients as many as you want to add

Opcode.java:

Operation code that is used to set a client-server communication protocol

package com.chat;

/**************** an interface to define different operation code **************/

public interface Opcode {
int CLIENT_CONNECTEING = 1;
int CLIENT_CONNECTED = 2;
}

LiveChatServer.java:

Single server that is controlling multiple clients

package com.chat;

/************************ Live Chat Server *******************/

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedHashMap;

public class LiveChatServer {

// Connection state info
private static LinkedHashMap<String, ClientThread> clientInfo = new LinkedHashMap<String, ClientThread>();

// TCP Components
private ServerSocket serverSocket;

// Main Constructor
public LiveChatServer() {

startServer();// start the server
}

public void startServer() {
String port = "1234";

try {
// in constractor we are passing port no, back log and bind address whick will be local
// host
// port no - the specified port, or 0 to use any free port.
// backlog - the maximum length of the queue. use default if it is equal or less than 0
// bindAddr - the local InetAddress the server will bind to

int portNo = Integer.valueOf(port);
serverSocket = new ServerSocket(portNo, 0, InetAddress.getLocalHost());
System.out.println(serverSocket);

System.out.println(serverSocket.getInetAddress().getHostName() + ":"
+ serverSocket.getLocalPort());

while (true) {
Socket socket = serverSocket.accept();
new ClientThread(socket);
}
} catch (IOException e) {
System.out.println("IO Exception:" + e);
System.exit(1);
} catch (NumberFormatException e) {
System.out.println("Number Format Exception:" + e);
System.exit(1);
}
}

public static HashMap<String, ClientThread> getClientInfo() {
return clientInfo;
}

// *********************************** Main Method ********************

public static void main(String args[]) {
new LiveChatServer();
}

}

LiveChatClient.java:

Multiple clients talking to each other via server

package com.chat;

/************************ Live Chat Client *******************/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;

public class LiveChatClient {
private String chatName;// current user's chat name(max 7 char if greater than show as 6
// char+...
private String serverAddress;

// TCP Components
private Socket socket;
private BufferedReader in;
private PrintWriter out;

public LiveChatClient() {

initHostName();
runClient();// have fun
}

public void initHostName() {
try {
//replace host name with your computer name or IP address
serverAddress = "[hostname]";
if (serverAddress == null)
System.exit(1);

serverAddress = serverAddress.trim();
if (serverAddress.length() == 0)// empty field
{
System.out.println("Server IP Address or Name can't be blank.");
initHostName();
return;
}
System.out.println("Trying to connect with server...\nServer IP Address:"
+ serverAddress);

// create socket
InetAddress inetAddress = InetAddress.getByName(serverAddress);
if (!inetAddress.isReachable(60000))// 60 sec
{
System.out
.println("Error! Unable to connect with server.\nServer IP Address may be wrong.");
System.exit(1);
}

initPortNo();
} catch (SocketException e) {
System.out.println("Socket Exception:\n" + e);
initHostName();
return;
} catch (IOException e) {
initHostName();
return;
}
}

public void initPortNo() {
try {

String portNo = "1234";

portNo = portNo.trim();
if (portNo.length() == 0)// empty field
{
System.out.println("Server port No can't be blank.");
initPortNo();
return;
}
System.out.println("Trying to connect with server...\nServer Port No:" + portNo);

socket = new Socket(serverAddress, 1234);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

} catch (IOException e) {
System.out.println("IO Exception:\n" + e);
initPortNo();
return;
}
}

public void sendChatName() throws IOException {
System.out.println("Enter your name:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String name = br.readLine();
if (name == null)
System.exit(1);

// title case (get only first 9 chars of chat name)
name = name.trim();

if (name.equalsIgnoreCase("All")) {
System.out.println("This name is already reserved. Try different one.");
sendChatName();
return;
}
if (name.length() == 0) {
System.out.println("Please enter your chat name.");
sendChatName();
return;
}
if (name.length() == 1)
chatName = String.valueOf(name.charAt(0)).toUpperCase();
if (name.length() > 1 && name.length() < 10)
chatName = String.valueOf(name.charAt(0)).toUpperCase()
+ name.substring(1).toLowerCase();
else if (name.length() > 9)
chatName = String.valueOf(name.charAt(0)).toUpperCase()
+ name.substring(1, 10).toLowerCase();

// sending opcode first then sending chatName to the server
out.println(Opcode.CLIENT_CONNECTEING);
out.println(chatName);
}

public void runClient() {
try {
sendChatName();
while (true) {
int opcode = Integer.parseInt(in.readLine());
switch (opcode) {
case Opcode.CLIENT_CONNECTEING:
// this client is connecting
boolean result = Boolean.valueOf(in.readLine());
if (result) {
System.out
.println(chatName + " is already present. Try different one.");
runClient();
}

break;

case Opcode.CLIENT_CONNECTED:
// a new client is connected
Integer totalClient = Integer.valueOf(in.readLine());
System.out.println("Total Client:" + totalClient);

for (int i = 0; i < totalClient; i++) {
String client = in.readLine();
System.out.println((i + 1) + ":" + client);
}

break;

}
}
} catch (IOException e) {
System.out.println("Client is closed...");
}
}

// *********************************** Main Method ********************

public static void main(String args[]) {
new LiveChatClient();
}

}

ClientThread.java:

Multiple thread started by server one for each client and containing information about all connected clients

package com.chat;

/************************ Client Thread *******************/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;

public class ClientThread implements Runnable {
// TCP Components
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private String chatName;

// seperate thread
private Thread thread;

// boolean variable to check that client is running or not
private volatile boolean isRunning = true;

// opcode
private int opcode;
private HashMap<String, ClientThread> clientInfo = new HashMap<String, ClientThread>();

public ClientThread(Socket socket) {
try {
this.socket = socket;
this.clientInfo = LiveChatServer.getClientInfo();

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

thread = new Thread(this);
thread.start();

} catch (IOException e) {
System.out.println(e);
}
}

public void run() {
try {
while (isRunning) {
if (!in.ready())
continue;

opcode = Integer.parseInt(in.readLine());// getting opcode first from client
switch (opcode) {
case Opcode.CLIENT_CONNECTEING:
chatName = in.readLine();

boolean result = clientInfo.containsKey(chatName);
out.println(Opcode.CLIENT_CONNECTEING);
out.println(result);
if (result)// wait for another chat name if already present
continue;

// send list of already online users to new online user
// for (Object user : clientInfo.keySet().toArray()) {
// out.println(Opcode.CLIENT_CONNECTED);
// out.println(user.toString());
// }

// put new entry in clientInfo hashmap
clientInfo.put(chatName, this);

int i = 0;
for (String key : clientInfo.keySet()) {
if (key.equals(chatName)) {
System.out.println(chatName + " added at " + (i + 1) + " position");
}
i++;
}

// tell other users about new added user and update their online users list
for (ClientThread client : clientInfo.values()) {
client.out.println(Opcode.CLIENT_CONNECTED);
client.out.println(clientInfo.size());

for (ClientThread client1 : clientInfo.values()) {
client.out.println(client1.chatName);
}
}

break;
}
}

// clsoe all connections
out.close();
in.close();
socket.close();
} catch (IOException e) {
System.out.println(e);
}
}
}

Here is the output when two client are added.

Server:

ServerSocket[addr=computerName/IPAddress,port=0,localport=1234]
computerName:1234
Abc added at 1 position
Xyz added at 2 position

Client 1:

Trying to connect with server...
Server IP Address:computerName
Trying to connect with server...
Server Port No:1234
Enter your name:
abc
Total Client:1
1:Abc
Total Client:2
1:Abc
2:Xyz

Client 2:

Trying to connect with server...
Server IP Address:computerName
Trying to connect with server...
Server Port No:1234
Enter your name:
xyz
Total Client:2
1:Abc
2:Xyz


Related Topics



Leave a reply



Submit