15. september 2011 - 21:21Der er
36 kommentarer og 1 løsning
Java Server Socket Program
Så jeg har leget lidt med at lave et multi-threaded Server Program i java.. men jeg er begyndt at tvivle på min arkitektur, og skulle høre om denne måde jeg gør det på er inde for en god standart.
Jeg har min main thread, som indeholder Array med alle client socket tråde Socket variabel med main server socket tråd Terminal input/output
Main starter en server socket i den egen tråd.
Server socket tråden, vil så og vente på en forbindelse, som den så vil slynge over i en af clientsocket arrays tomme eller døde Threads.
for at lave det lidt mere virsuelt, har jeg lavet et billede i paint, som kan forklare det lidt bedre, håber jeg :)
jeg vil så meget gerne høre om denne ide er "ok" eller om den absolut ikke skal bruges på den måde. og hvad det bedste alternativ kunne være.
Laver main traaden noget eller venter den bare? Hvis den bare venter kunne du flytte server listener funktionaliteten over i den.
En traad per client er et helt standard design. Det er relativt nemt at implementere. Du boer ikke bruge den med mange klienter. Jeg ville skifte design omkring de 500 samtidige klienter.
main tråden ville jeg gerne bruge til at "broadcaste" beskeder til alle tåde... jeg har prøvet lidt at have det altsammen i Serversocket tråden, men siden den vil stå og vente med serversocket.accept.
var jeg nød til at lave en ny tråd, der kunne køre et
While(true) { thread.sleep(25); }
hvor jeg ville kunne styre f.eks et spils logik i.
ligenu leger jeg bare med det, så har prøvet at lave en lille chat server. hvor main tråden har et array, med et objekt jeg kalder "messages", med 2 data "dato" og "besked".
hver gang clientsocket får en ny besked i indputstream, sender den det som et object, og tilbføjer det til arrayet.
hver gang der er nye beskeder, som er yngre end sidste gange clientsocket checkede.. vil den hente dem, og udskrive dem til outputstream.
men må man det? altså få så mange tråde til at skrive til samme array? eller findes der en bedre måde at gøre det på?
jeg vil præcis os bruge hver tråd, ved at læse samme sted fra i min main tråd :)
hmmm jeg har ikke rigtigt arbjedet med synhronized før, så skal lige læse op på det.. men jeg går ud fra det har noget at gøre med at kun 1 tråd læser fra dataarkivet af gangen?
Synes godt om
Slettet bruger
15. september 2011 - 21:47#5
Har du kun én tråd til at skrive data ud til samtlige sockets der lytter? Du kan godt risikere at en enkelt socket blokerer denne tråd hvis den er sløv til at læse de data du skriver til den. Hvis det er til chat fungerer det sikkert fint, men til spil vil du opleve lag.
Java giver dig mulighed for at læse og skrive data asynkront med java.nio. Du slipper for 1-2 tråde per klient (read+write), og kan køre det hele med en enkelt tråd. Til gengæld skal du bruge nogle buffere til at lagre de stumper af data du får læst/sendt, så det gør det ikke nødvendigvis mere simpelt at lave, men serveren vil køre meget mere smidigt.
hmm.. jeg lagt lige hurtigt en kode sammen.. for at vise hvad jeg har gjort.
jeg ved godt min messages array kun har begrænset antal pladser, men jeg gad ikke til at lave roteringen færdig.
men håber i kan se min ide og tankegang
myServer (main class)
package server;
import java.net.*;
public class myServer {
protected String version = "1.0"; //versions nummer for at tjekke protokol version protected Thread sst; //Variabel som holder ServerSocket Tråden protected Thread[] cst; //Array med alle Client Socket Trådene private int port; //Port private int slots; //max antal clienter som kan tilslutte
public static void main(String[] args) { myServer mS = new myServer(); mS.setPort(18778); mS.setSlots(2); mS.run(); }
public void setPort(int port){ this.port = port; } public int getPort(){ return this.port; } public void setSlots(int slots){ this.slots = slots; } public int getSlots(){ return this.slots; }
public void run(){ cst = new Thread[this.getSlots()]; this.messages = new Message[100]; System.out.println("Starter Server"); System.out.println("Lytter på port: "+ this.getPort()); sst = new Thread(new ServerSocketThread(this)); //ligger ServerSocketThread i tråd, med ref til myServer sst.start(); //starter Serversocket tråd } }
ServerSocketThread
package server;
import java.net.*; import java.io.*; public class ServerSocketThread implements Runnable{
myServer server; //bliver ref til myServer main tråden ServerSocket ss; //bliver ServerSocket
public ServerSocketThread(myServer server){ this.server = server; //laver referancer til main thread }
@Override public void run() {
try { ss = new ServerSocket(server.getPort()); //opretter ServerSocket
while(true) { Socket cs; //opretter clientsocket cs = ss.accept(); //overføre forbindelse til clientsocket System.out.println("Forbindelse fra "+ cs.getInetAddress().getHostAddress());
ClientSocketThread tempcst = new ClientSocketThread(cs,server); for(int i = 0;i<server.cst.length;i++) //køre array igennem af tråde { if(server.cst[i] == null || !server.cst[i].isAlive()){ //hvis denne tråd ikke bliver brugt server.cst[i] = new Thread(tempcst); //ligger den indkommende client socket i sin egen tråd tempcst.isAssigned = true; tempcst.clienID = i; server.cst[i].start(); break; } } if(tempcst.isAssigned == false){ System.out.println("SERVER: kunne ikke forbinde, ikke nok slots"); cs.close(); } }
public class ClientSocketThread implements Runnable{
public boolean isAssigned; //om denne er blevet lagt i array på ServerSocketThread public int clienID = 0; protected Socket cs; //client Socket ref protected myServer server; //ref til Main Thread
private double lastmessage = 0; private PrintWriter out = null; //udegående tekst private BufferedReader in = null; //indgående tekst
@Override public void run() { try { out = new PrintWriter(this.cs.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(this.cs.getInputStream())); } catch (IOException ex) {}
Det eneste jeg lige kan kommentere på ud fra den kode du har vist, er at du bruger Reader og Writer uden at specificere hvilken encoding de skal bruge, og det kan give nogle problemer hvis din server f.eks. kører på Windows og bruger windows-1252 som default, mens en klient på en anden platform bruger noget andet som default. Du kan med InputStreamReader og OutputStreamWriter på server og klient kode fortælle hvilken encoding de skal bruge (f.eks. UTF-8), så det er ens uanset hvilken platform du kører server og klient på.
jeg havde et problem med readline, at den stopper koden, til noget kommer i den.. jeg ved ikke om det stemmer?
også havde jeg også tænkt mig at udvikle på main tråden så den gav lidt mere mening, det var blot en demonstration på hvad jeg mente :)
men havde tænkt at ligge noget GameLogic i Main Tråden, og nogen lidt andre objekter..
også lave 2 typer variabler.. en med input.. og en til de behandlede data...
f.eks en lang liste af alle Clienters bevægelser, hvor Main TRåden så tog den sidste bevægelse, og lage dem til at blive hentet af da andre clienter...
som sagt, jeg kunne have brugt længere tid på den kode, men det var kun et eksempel, for at se hvad i sagde til det.. jeg har aldrig tænkt mig at bruge det, men mere for at forstå ideen, med at kunne kommunikere mellem tråde :)
jeg syntes ikke der har været noget om at jeg laver reference til myServer ind over tråde? det er der måske intet problem i?
nu er hele dette spørgsmål os mest om at lave nogen gode standarter, og ikke bare klaske en lagkage sammen med en spade.. og hvad jeg kan høre, så er der en del jeg ikke har styr på.. som read/write Streams, data sending og andre vigtige ting.
Jeg kan stadig ikke få synchronized til at virke.. jeg lavede denne methode, men noget siger mig jeg har misforstået ideen med det.
public synchronized void SendMessageGlobal(String message){ server.messages[0] = new Message(System.currentTimeMillis(),"Klient #"+this.clienID+": "+message); }
for kan ikke helt forstå hvordan man så får synkroniseret en delt variabel..
jeg må lige finde nogen tutorials på den pokkers synchronized, for jeg prøvede lidt med det, og kunne ikke få den til at fungere med synchronized(){} jeg havde ingen ide om hvordan jeg skulle få det til at se ud :)
Men proev og koer dette (og studer det saa bagefter):
public class ToSyncOrNotToSync { private static final int NTHREAD = 100; private static final int NREP = 1000000; private int n; public void incrN() { n++; } public void testNonSynch() throws InterruptedException { n = 0; Thread[] t = new Thread[NTHREAD]; for(int i = 0; i < t.length; i++) { t[i] = new NonSyncThread(this, NREP); } long t1 = System.currentTimeMillis(); for(int i = 0; i < t.length; i++) { t[i].start(); } for(int i = 0; i < t.length; i++) { t[i].join(); } long t2 = System.currentTimeMillis(); System.out.println((NTHREAD*NREP) + "=" + n + " in " + (t2-t1) + " ms"); } public void testSynch() throws InterruptedException { n = 0; Thread[] t = new Thread[NTHREAD]; for(int i = 0; i < t.length; i++) { t[i] = new SyncThread(this, NREP); } long t1 = System.currentTimeMillis(); for(int i = 0; i < t.length; i++) { t[i].start(); } for(int i = 0; i < t.length; i++) { t[i].join(); } long t2 = System.currentTimeMillis(); System.out.println((NTHREAD*NREP) + "=" + n + " in " + (t2-t1) + " ms"); } public static void main(String[] args) throws InterruptedException { ToSyncOrNotToSync o = new ToSyncOrNotToSync(); o.testNonSynch(); o.testSynch(); } }
class NonSyncThread extends Thread { private ToSyncOrNotToSync parent; private int nrep; public NonSyncThread(ToSyncOrNotToSync parent, int nrep) { this.parent = parent; this.nrep = nrep; } public void run() { for(int i = 0; i < nrep; i++) { parent.incrN(); } } }
class SyncThread extends Thread { private ToSyncOrNotToSync parent; private int nrep; public SyncThread(ToSyncOrNotToSync parent, int nrep) { this.parent = parent; this.nrep = nrep; } public void run() { for(int i = 0; i < nrep; i++) { synchronized(parent) { parent.incrN(); } } } }
jeg giver dig helt ret i det spørgsmål, heller sikker end usikker :) jeg er glad for alle dine gode inputs, og jeg har taget godt hånd om dem... jeg prøver at få implementeret de tips så godt jeg kan.. vil du ligge et svar, så vi kan få afsluttet denne lange tråd? jeg kan jo altid spørge videre i et nyt spørgsmål hvis jeg får problemer, men jeg tror denne er ved at være langt over lukketid, da jeg har fået meget mere end jeg forventet, rigtigt god input :)
det er rigtigt.. venter lige til han os ligger et svar
Synes godt om
Slettet bruger
16. september 2011 - 20:32#35
Ellers tak. Og fortsæt endelig din eksperimentering med client/server programmering. Det har jeg selv haft meget sjovt med, og samtidig lærer man en hel del om hvordan man bruger threads (her er wait() og notify() metoderne også interessante at sætte sig ind i).
Saa hvis man kan noejes med at bruge noget fra java.util.concurrent er det nok bedre.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.