I’m using the Network library. My Processing sketch opens a server. From external programs, I start one or more clients, which can send “commands” to the server, to make it doing something. This works fine.
My question is: is there a way to send a “reply” from the server ONLY to the client which sent the command? The doc for the Network library says that server.write(val) will send val to ALL the connected clients.
Thank you,
Giulio
Not tested but I think that based on the server’s source code how it write to all connected clients:
You just need to call “client of interest”.write(data). One way to check a client of interest is using the serverEvent(): serverEvent() / Libraries / Processing.org as it gives you a handle of the client that connects. You keep track of clients connection through a private array.
Kf
Dear Kf,
first, thank you very much for your immediate reply!. I tried your suggestion, and, contrary to what one might think by reading the doc for the Network library, it seems to work fine.
Best regards,
Giulio
that’s a chance for me, because i have to create (from an app already coded and working) some multiplayer version for on line tournaments. As the first app was written mainly with processing for its desktop version (there is also an android version but with AS) i decided to continue and so to use the network library. I had the same problem and solved it exactly as @kfrajer explained; but now i have another one for which i have not found any solution nor hint till now: it happens in the game (card game) that one player decides to leave and, as i have arrays where are registered all the nicknames and numbers of players, i must know when he is disconnecting in order to remove it from the arrays. I have seen that when some client disconnects the console is returning a red message about the Client (something like end of stream) and yet i cannot capture this message (which seems to be an exception); of course, client side, i cannot ask to the user to “send” a n exiting message; people can quit at any moment: so i have to get the exception server side. I have tried using serverEvent but unsucessfully (eg creating an array with the ip and trying to see if the size of the array changes and so on, but it does not work…Any idea??? - Thanks in advance. As for now il will try to have a look to the library source, if i found it.
BTW: i think that the network lib doc is not well structured: you go to server and you dont see any “related” reference to Client or serverEvent…
ok; i have got the lib source: here: https://github.com/processing/processing/tree/master/java/libraries/net/src/processing/net
but serverSide i cannot see the exception i am looking for: must be in the java io code, another problem! - Yet, i see in the code that there is a clients array and a int client count: will try to use that…
@akenaton Unfortunately I cannot check the code. I can have a look at it tonight. I evene remeber seeing some code managing the clients from the server side. It might be a contributed library, maybe the socket library. I think you can find it if you go to the prev forum and search for publications/contributions section posting.
For client and server event, I usually check the limited documentation by going to processing.org >> Libraries >> Network (it is in the top of the page, libraries that come with Processing) and you should be able to see the documented functions. I apologize I cannot provide links as my firewall right now is restrictive. I hope this helps,
Kf
@kfrajer===
Till now i am able to use the server to manage a lot of things / clients (mine can be 100 or more…) but i cannot see how to manage the disconnected event; i have found the src code: nothing that could solve the problem i think, though, for sending to all clients it creates an array and use it for removing some client, if needed; but i do not want that the server “decides” to remove a client, i want the client who has decided to leave the game (shutting down the app) to be removed from the connected array (indexCount–) and that the game goes on without this player.
This is what you need so I believe:
Description: This function is called when a client disconnects.
Check this link related to websockets: It shows how it manages the client. Notice this is not the same as the net library: https://github.com/alexandrainst/processing_websockets/blob/master/src/WebsocketServerController.java
Other links of interest, but possibly not relevant to you:
GitHub - alexandrainst/processing_websockets: A web socket library, including both server and client, for Processing
http://ubaa.net/shared/processing/udp/
GitHub - cansik/artnet4j: Art-Net DMX over IP library for Java and Processing
Carnivore
Kf
yes, this function is called when client disconnects but that is clientSide: and you cannot transmit it to the Server: Client got end-of-stream!!!
( i know the other links: some are irrelevant as for UDP or carnivore and as for websockets, which is the more interesting i dont remember why but i have decided that it was not ok for this project…I have also tried with node.js and even with Pusher…but they are rather ok for javaScript && P5JS, execept Pusher, which seems to have some unofficial library for httpRequests from Java)
I see now what you mean. I will have a look tonight if I can find some info that could help. What were you trying to do with node.js?
I have an idea but it is probly too much for this. If the client disconnects, he send a post request to your server through an independent channel.
Related to websockets, I understnad that there is continuos pooling between server and client. This is how they update each other in real time, or even they could detect a disconnection. I am not sure hwat is the approach by the net library, if they are just issuing http inquires for each request. I can tag @shiffman or @koogs as they might know.
@jeremydouglass Do you know by any chance koogs id in this new forum? Is he dan385?
Kf
So I have something you can use. I didn’t go into the source code but I did a layer on top to keep track of the clients on the server side, and for the clients to remember what id they each get assigned by the server during the connection process.
IMPORTANT: Do not stop the sketch using the stop button in the PDE. Instead, close the sketch only by hitting/clicking the x button in the sketch window. To fix this issue, a proper exit() function needs to be implemented. Not important at the moment but just keep in mind.
Notice also it is very important that the server is open first followed by the clients, and likewise, the server is closed last.
When a client connects to the server, the client receives a tag id from the server which the client stores internally. The server keeps track of these tags.
If you click in the client’s sketch, it send a message to the server and the sender relays this msg back to the client.
when a client disconnects (the sketch window is closed via the x button of the sketch window), the client issues a disconnection which is captured by the server. The server proceeds to remove the id from the mist of connected clients.
While running this code, server-client connection failed few times which affected my mouseEvents in Windows. Hopefully mouseEvents work for you.
Kf
P.S. You can run multiple clients. Just assigned a diff color to each sketch.
SERVER
// Creates a server that prints new client's IP addresses.
import processing.net.*;
final String SEP=":";
int port = 12009;
Server myServer;
IntList myClientsList;
void setup()
{
size(400, 400);
myServer = new Server(this, port); // Starts a server on port 10002
fill(220);
textSize(18);
myClientsList=new IntList();
}
void draw() {
// Nothing happens here, everything happens inside ServerEvent()
background(180, 0, 0);
text("Server", 0, height/2);
// Get the next available client
Client thisClient = myServer.available();
// If the client is not null, and says something, display what it said
if (thisClient !=null) {
String whatClientSaid = thisClient.readString();
println("Received from client at " + millis()+" ms");
if (whatClientSaid != null) {
String[] lines=split(whatClientSaid, SEP);
if (lines.length==1) {
println(thisClient.ip() + " says >>" + whatClientSaid + "<<");
myServer.write(str(frameCount));
} else if (lines.length==2) {
if (lines[0].equals("disconnect")) {
int clientid=int(trim(lines[1]));
if (myClientsList.hasValue(clientid)) {
//Removes clientid located in array at index based on index() function
myClientsList.remove(myClientsList.index(clientid));
println("Client #"+clientid+" was removed. Number of clients connected=" + myClientsList.size());
} else {
//Something seriously wrong
println("FATAL server error. Client id#"+clientid+" issue disconnection but not found in server. Why?");
}
}//Processing two tokes: disconnection
} else {
println("FATAL server error. I got more than two tokens during parsing msg. Why?");
}
}
} // thisClient !=null
}
// ServerEvent message is generated when a new client connects
// to an existing server.
void serverEvent(Server someServer, Client someClient) {
println("We have a new client: " + someClient.ip());
//Generate random index as we have a new client. Ensures indes is not assigned
int clientid=-1; //Not assigned
while (clientid<0 || myClientsList.hasValue(clientid))
clientid=int(random(1)*100000);
myClientsList.append(clientid);
myClientsList.sort();
someClient.write("helloWithID"+SEP+clientid);
println("WELCOME client #"+clientid+". Current clients in queu:"+myClientsList.size());
printArray(myClientsList.array());
}
CLIENT
import processing.net.*;
final String SEP=":";
Client c;
int clientid=-1; //Not assigned
void setup() {
size(400, 200);
fill(220);
textSize(18);
c = new Client(this, "192.168.1.67", 12009); // Connect to server on port 8080
}
void draw() {
background(0, 180, 0);
text("Client", 0, height/2);
if (c.available() > 0) {
// Read in the bytes
byte[] byteBuffer = new byte[1024];
int byteCount = c.readBytes(byteBuffer);
if (byteCount > 0 ) {
// Convert the byte array to a String
String myString = new String(byteBuffer);
println("Received from server at " + millis()+" ms");
String[] lines=split(myString, SEP);
if (lines.length==1) {
println(c.ip() + " says >>" + myString + "<<");
c.write(str(frameCount));
} else if (lines.length==2) {
if (lines[0].equals("helloWithID")) {
clientid=int(trim(lines[1]));
println("Assigned id ta#"+clientid+" by server.");
}//Processing two tokes: disconnection
} else {
clientid= -99;
println("FATAL client error. I got more than two tokens during parsing msg. Why?");
}
} //byteCount>0
}
}
void mouseReleased() {
c.write(str(frameCount));
println("Send=>" + str(frameCount));
}
void exit() {
disconnectEvent(c);
}
void disconnectEvent(Client someClient) {
print("Server Says: ");
int dataIn = someClient.read();
println("DISCONNECTION issued: " + clientid);
someClient.write("disconnect"+SEP+clientid);
println("Read from server=>" +dataIn);
}
@kfrajer===
yes, with your code the red error does not appear anymore and the numbers of clients is well updated, but the exit() method is not executed and the app is still alive… i get exactly the same result with my code if i dont hit the ide stop button but the x; as for now i see only one solution though it is against the user behaviour: create some button called “Quit” or KeyPressed event, when it is fired use the disconnectedevent from clientSide (like your code), adding exit() at this moment, after the message was send to the Server: in this case everything works except that i get (clientside) some red exception (socket closed) which does not matter (i hope!!!) as the player has left…
But it is against the users behaviours!!!
void keyPressed(){
if(key == 'Q'){
disconnectEvent(c);
}
}
void disconnectEvent(Client someClient) {
print("Server Says: ");
int dataIn = someClient.read();
println("DISCONNECTION issued: " + clientid);
someClient.write("disconnect"+SEP+clientid);
println("Read from server=>" +dataIn);
delay(100);
if(dataIn==-1){
exit();
}
//someClient=null;
}
Hi Kf, coming back to my original question: in fact, as “client.write(data)” works on the Server side, the solution is even simpler. When a client sends a message to the server, its client_id is returned by server.available(). One uses that client_id to read the message, and then uses it again to send back the reply to the client.
In this simple scenario, no need to deal with server_Event, or to maintain a list of connected clients.
Best regards,
Giulio
In reality, disconnectEvent works on the Server side, and lets you know the client id of the client which disconnected from the Server. I think the last few lines of code in the doc for it are wrong (they seem cut/pasted from the clientEvent example).
I tried it in my server, to see if I can get rid of the red message “client got end-of-stream”.
The message does not go away, but disconnectEvent does what I just described above.
Giulio
@giulio===
i know that; the problem i have solved with my workaround (creating a quit event) is if you dont use that the app remains running even after disconnecting and that i cannot remove the client from the server list (client end-of-seam makes that no message can be send, of course) which is mandatory in my case…
I think you can remove the client from the server list, as you can get the client_id in the disconnectEvent function.
Anyway, my (prototype) model is different: I start a server, to whom “any” number of client (which are not implemented in Processing) can connect, send one or more “messages”, possibly getting replies from the server, and then they can disconnect (and possibly reconnect later).
To give you a better idea, some of the messages are parameters for a function that the server displays; another message passes a string to the server which replies by sending back the same string repeated twice.
When a client disconnects, the server does not bother at all. Its task is to be ready to serve whatever client needs a service.
Giulio
@giulio===
my case is not the same
it s a multiplayer (>100) game, players choosing partners and playing in a room: so the server has to get a list of all the players connected (- those already playing, + - those quitting the game) and update it; of course the server dose not bother, as you say, when a player is quitting, but what about the list of connected players? It has to be updated! - So a) the disconnect event has to be captured client side and transmit to the server: that is what my code tries to do and it runs except in the case the user instead of typing Q hits the stop button of the app…
@akenaton This is happening on the client side? I believe the exit method is only executed when you close the window hitting the x button in the top right corner of a sketch. Maybe pressing the ESC button as well. It does not work if you stop the sketch from the PDE.
Kf
@kfrajer===
try to export an app
you can see that it remains running even when you hit the x button of it!
try the same with my code (keyPressed), the app closes…
I see now, good to know. I think you should be able to override dispose()
N.B. not tested.
Ok, when do we get to play your game? Running the game in a clse network?
Kf