ࡱ> M Rbjbj== .WWMl&&&&&&&:|7|7|7|7L7:>888888>88  $ҙ -!&88888-9&&88N9998&8&8989< 9$CM&&8|8 LҺ:B1|78"d0199::&&&&Internet Programming with Java Course 1.10 @8<5@: 07@01>B:0 =0 Forward AJ@2J@ Multithreaded Forward Server with Load Balancing and Failover Features  Multithreaded Forward Server Implementation  Nakov Forward Server /** * Nakov TCP Socket Forward Server - freeware * Version 1.0 - March, 2002 * (c) 2001 by Svetlin Nakov - http://www.nakov.com * * Short decription: Nakov Forward Server is designed to forward (redirect) TCP * connections from a client to a server choosen from a servers list. When a client * is connected to Nakov Forward Server, a new connection is opened to some of the * specified destination servers and all the traffic from destination server to * Nakov Forward Server is redirected to the client and also all the traffic from * the client to Nakov Forward Server is redirected to destination server. That * way Nakov Forward Server makes transparent redirection of TCP connections. * The data transfer schema is the following: * * CLIENT <--> NAKOV_FORWARD_SERVER <--> DESTINATION_SERVER * * Clients and Destination Servers communicate only with Nakov Forward Server. * * Nakov Forward Server supports failt tolerance. When some of the servers in the * list fail to respond to TCP connect request (dead server), Nakov Forward Server * tries the next server in the list until it finds alive server. All dead servers * are checked if they are alive through some time interval and when some server * becomes available, it is added to alive list. When no server is alive, no * connection will be established. * * Nakov Forward Server supports also load balancing features. If load balancing * is enabled, when a client connection is accepted, Nakov Forward Server will * redirect the client to the least loaded server from the servers list. We consider * the server which hast minimal alive connections established by Nakov Forward * Server is least loaded. * * What we gain when we use Nakov Proxy Server? * - Destination server does not know the real IP of the client. It thinks * that the IP of Nakov Forward Server is its client. Thus we can use a server * licensed for one IP address on several machines simultaneously. * - Nakov Forward Server can run on a port number that is allowed by the * firewall and forward to a port number that is not allowed by firewall. Thus, * started on a server in a local network, it can give access to some disabled * by the firewall services. * - Nakov Forward Server can give access to multiple clients to some service * that is allowed only for some fixed IP address when started on the machine * with this IP. * - Fault Tolerance (failover) of Nakov Forward Server helps to avoid faults * when some of the servers die. Of course there is special hardware for this, but * it has high price. Instead you can use Nakov Forward Server (that is free). * If you setup several Nakov Forward Servers configured to use the same set of * destination servers and if you configure your routers to use redirect traffic * to both servers, you will obtain a stable fault tolerance system. In such a * system you have guarantee that crash of any of the servers (including some of * the Nakov Forward Servers) will not stop the service that these servers provide. * Of course the destination servers should run in a cluster and replicate their * sessions. * - Load balancing helps to avoid overloading of the servers by distributing * the clients between them. Of course this should be done by special hardware * called "load balancer", but if we don't have such hardware, we can still use * this technology. When we use load balancing, all the servers in the list should * be running in a cluster and there should be no matter what of the servers the * client is connected to. The servers should communicate each other and replicate * their session data. * * NakovForwardServer.properties configuration file contains all the settings of * Nakov Forward Server. The only mandatory field is "Servers" * Destination servers should be in following format: * Servers = server1:port1, server2:port2, server3:port3, ... * For example: * Servers = 192.168.0.22:80, rakiya:80, 192.168.0.23:80, www.nakov.com:80 * Nakov Forward Server listening port should be in format: * ListeningPort = some_port (in range 1-65535) * Using load balancing algorithm is specified by following line: * LoadBalancing = Yes/No * Check alive interval through which all dead threads should be re-checked if * they are alive is specified by following line: * CheckAliveInterval = time_interval (in milliseconds) */ import java.util.ArrayList; import java.net.ServerSocket; import java.net.Socket; import java.net.InetAddress; import java.io.IOException; import java.io.FileInputStream; import java.util.Properties; import java.util.StringTokenizer; public class NakovForwardServer { private static final boolean ENABLE_LOGGING = true; public static final String SETTINGS_FILE_NAME = "NakovForwardServer.properties"; private ServerDescription[] mServersList = null; private int mListeningTcpPort = 2001; private boolean mUseLoadBalancingAlgorithm = true; private long mCheckAliveIntervalMs = 5*1000; /** * ServerDescription descripts a server (server hostname/IP, server port, * is the server alive at last check, how many clients are connected to it, etc.) */ class ServerDescription { public String host; public int port; public int clientsConectedCount = 0; public boolean isAlive = true; public ServerDescription(String host, int port) { this.host = host; this.port = port; } } /** * @return an array of ServerDescription - all destination servers. */ public ServerDescription[] getServersList() { return mServersList; } /** * @return the time interval (in milliseconds) through which all dead servers * should be re-checked if they are alive (a server is alive if accepts * client connections on the specified port, otherwise is dead). */ public long getCheckAliveIntervalMs() { return mCheckAliveIntervalMs; } /** * @return true if load balancing algorithm is enabled. */ public boolean isLoadBalancingEnabled() { return mUseLoadBalancingAlgorithm; } /** * Reads the Nakov Forward Server configuration file "NakovForwardServer.properties" * and load user preferences. This method is called once during the server startup. */ public void readSettings() throws Exception { // Read properties file in a Property object Properties props = new Properties(); props.load(new FileInputStream(SETTINGS_FILE_NAME)); // Read and parse the server list String serversProperty = props.getProperty("Servers"); if (serversProperty == null ) throw new Exception("The server list can not be empty."); try { ArrayList servers = new ArrayList(); StringTokenizer stServers = new StringTokenizer(serversProperty,","); while (stServers.hasMoreTokens()) { String serverAndPort = stServers.nextToken().trim(); StringTokenizer stServerPort = new StringTokenizer(serverAndPort,": "); String host = stServerPort.nextToken(); int port = Integer.parseInt(stServerPort.nextToken()); servers.add(new ServerDescription(host,port)); } mServersList = (ServerDescription[]) servers.toArray(new ServerDescription[] {}); } catch (Exception e) { throw new Exception("Invalid server list format : " + serversProperty); } if (mServersList.length == 0) throw new Exception("The server list can not be empty."); // Read server's listening port number try { mListeningTcpPort = Integer.parseInt(props.getProperty("ListeningPort")); } catch (Exception e) { log("Server listening port not specified. Using default port : " + mListeningTcpPort); } // Read load balancing property try { String loadBalancing = props.getProperty("LoadBalancing").toLowerCase(); mUseLoadBalancingAlgorithm = (loadBalancing.equals("yes") || loadBalancing.equals("true") || loadBalancing.equals("1") || loadBalancing.equals("enable") || loadBalancing.equals("enabled")); } catch (Exception e) { log("LoadBalancing property is not specified. Using default value : " + mUseLoadBalancingAlgorithm); } // Read the check alive interval try { mCheckAliveIntervalMs = Integer.parseInt(props.getProperty("CheckAliveInterval")); } catch (Exception e) { log("Check alive interval is not specified. Using default value : " + mCheckAliveIntervalMs + " ms."); } } /** * Starts a thread that re-checks all dead threads if they are alive * through mCheckAliveIntervalMs millisoconds */ private void startCheckAliveThread() { CheckAliveThread checkAliveThread = new CheckAliveThread(this); checkAliveThread.setDaemon(true); checkAliveThread.start(); } /** * Starts the forward server - binds on a given port and starts serving */ public void startForwardServer() throws Exception { // Bind server on given TCP port ServerSocket serverSocket; try { serverSocket = new ServerSocket(mListeningTcpPort); } catch (IOException ioe) { throw new IOException("Unable to bind to port " + mListeningTcpPort); } log("Nakov Forward Server started on TCP port " + mListeningTcpPort + "."); log("All TCP connections to " + InetAddress.getLocalHost().getHostAddress() + ":" + mListeningTcpPort + " will be forwarded to the following servers:"); for (int i=0; i dest server out" and * "dest server in <--> client out", waits until one of these threads stop * due to read/write failure or connection closure. Closes opened connections. */ public void run() { try { mClientHostPort = mClientSocket.getInetAddress().getHostAddress() + ":" + mClientSocket.getPort(); // Create a new socket connection to one of the servers from the list mServerSocket = createServerSocket(); if (mServerSocket == null) { // If all the servers are down System.out.println("Can not establish connection for client " + mClientHostPort + ". All the servers are down."); try { mClientSocket.close(); } catch (IOException e) {} return; } // Obtain input and output streams of server and client InputStream clientIn = mClientSocket.getInputStream(); OutputStream clientOut = mClientSocket.getOutputStream(); InputStream serverIn = mServerSocket.getInputStream(); OutputStream serverOut = mServerSocket.getOutputStream(); mServerHostPort = mServer.host + ":" + mServer.port; mNakovForwardServer.log("TCP Forwarding " + mClientHostPort + " <--> " + mServerHostPort + " started."); // Start forwarding of socket data between server and client ForwardThread clientForward = new ForwardThread(this, clientIn, serverOut); ForwardThread serverForward = new ForwardThread(this, serverIn, clientOut); mBothConnectionsAreAlive = true; clientForward.start(); serverForward.start(); } catch (IOException ioe) { ioe.printStackTrace(); } } /** * connectionBroken() method is called by forwarding child threads to notify * this thread (their parent thread) that one of the connections (server or client) * is broken (a read/write failure occured). This method disconnects both server * and client sockets causing both threads to stop forwarding. */ public synchronized void connectionBroken() { if (mBothConnectionsAreAlive) { // One of the connections is broken. Close the other connection // and stop forwarding // Closing these socket connections will close their input/output streams // and that way will stop the threads that read from these streams try { mServerSocket.close(); } catch (IOException e) {} try { mClientSocket.close(); } catch (IOException e) {} mBothConnectionsAreAlive = false; mServer.clientsConectedCount--; mNakovForwardServer.log("TCP Forwarding " + mClientHostPort + " <--> " + mServerHostPort + " stopped."); } } /** * @return a new socket connected to some of the servers in the destination * servers list. Sequentially a connection to the least loaded server from * the list is tried to be established. If connecting to some alive server * fail, this server it marked as dead and next alive server is tried. If all * the servers are dead, null is returned. Thus if at least one server is alive, * a connection will be established (of course after some delay) and the system * will not fail (it is fault tolerant). Dead servers can be marked as alive if * revived, but this is done later by check alive thread. */ private Socket createServerSocket() throws IOException { while (true) { mServer = getServerWithMinimalLoad(); if (mServer == null) // All the servers are down return null; try { Socket socket = new Socket(mServer.host, mServer.port); mServer.clientsConectedCount++; return socket; } catch (IOException ioe) { mServer.isAlive = false; } } } /** * @return the least loaded alive server from the server list if load balancing * is enabled or first alive server from the list if load balancing algorithm is * disabled or null if all the servers in the list are dead. */ private NakovForwardServer.ServerDescription getServerWithMinimalLoad() { NakovForwardServer.ServerDescription minLoadServer = null; NakovForwardServer.ServerDescription[] servers = mNakovForwardServer.getServersList(); for (int i=0; i exit the thread mOutputStream.write(buffer, 0, bytesRead); } } catch (IOException e) { // Read/write failed --> connection is broken --> exit the thread } // Notify parent thread that the connection is broken and forwarding should stop mParent.connectionBroken(); } } /** * CheckAliveThread checks all dead servers in the server list and updates the * list when some dead server becomes alive. Checking is done on a beforehand * specified time itrervals. A server is considered alive if it accepts client * connections on the specified port. */ import java.io.IOException; import java.net.Socket; public class CheckAliveThread extends Thread { private NakovForwardServer mNakovForwardServer = null; /** * Creates a check alive thread. NakovForwardServer object is needed * for obtaining the servers list. */ public CheckAliveThread(NakovForwardServer aNakovForwardServer) { mNakovForwardServer = aNakovForwardServer; } /** * Until stopped checks all dead servers if they are alive and waits * specified time interval */ public void run() { while (!interrupted()) { try { Thread.sleep(mNakovForwardServer.getCheckAliveIntervalMs()); } catch (InterruptedException ie) { ie.printStackTrace(); } checkAllDeadServers(); } } /** * Checks all dead servers if they are alive and updates their state if needed. */ private void checkAllDeadServers() { NakovForwardServer.ServerDescription[] servers = mNakovForwardServer.getServersList(); for (int i=0; iN Om*./K7$8$H$Ki:<qQ#(ADZm7$8$H$^wxy}().FL\bcfouvylms,-3Z`67=>BiFOT(B*CJOJQJ^JaJmHnHphu(B* CJOJQJ^JaJmHnHphu(B* CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHuE"gl T',UX7$8$H$X}16RdgRr( O !;!n!s!!7$8$H$TVkouz{~ " % + 0 !!K!N!!!!!!!!!!"4"6"O"P"U"Z"["^"i""""""" ###/#k#######4$9$S$Y$s$v$$۱(B* CJOJQJ^JaJmHnHphu(B* CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B*CJOJQJ^JaJmHnHphuF!!!."2"R"""""#(#o#######>$$$$%A%E%F%i% 7$8$H$^7$8$H$R7$8$H$^R`$$$$$$$!%H%i%k%n%%%%%%'&B&H&U&&&&&&"'%'7';'['_'''''''(/(N(Q(f(i((((((((((()?)B)K)d)))))))))))**4*۱(B* CJOJQJ^JaJmHnHphu(B*CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B* CJOJQJ^JaJmHnHphuFi%q%%%%*&K&O&P&S&T&Y&&&&&&>'b'~''''''' ( (R7$8$H$^R`7$8$H$ (/(L(T((((((E)))*Q*U*}****++@++++ ,7$8$H$^`7$8$H$^`7$8$H$4*7*[*y**********+ + +++++ ,,+,/,`,e,z,,,,,,,0-1-7-8-<-W-Y-u-x-----... .?.B.[.^....-0000000&1*1-141d1h1k1r11111111(B*CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B* CJOJQJ^JaJmHnHphuN ,@,[,v,,,,,,,-+-0-R-U-k--------!.$.Y.a.x.7$8$H$7$8$H$^`x............D///(0,0-0E0f0000000,1j1&d7$8$H$P7$8$H$j1111 2+2,212y2222G3]3`3333334P44445557$8$H$^`7$8$H$111111 22-2223344444 5 5W5Z5z555566 6)64676@6j6666666666-7@8C8o88888889%9(979;9t9w999999:<:z;{;;;;;;;&<)<s<v<(B* CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B*CJOJQJ^JaJmHnHphuN5W5v5w555)6m666666-7g77788T88889S9999R7$8$H$^R`7$8$H$999:3:7:::;:@:::5;u;z;;;;<&<s<<</=0=U=x=y==7$8$H$^`7$8$H$v<<<<<<<<==N=S========]@^@e@@@@@@@@@@A AAAAAA6A9AAAAAAAABBBLCPCCCCCCCCCCC D DDDDDDD E۱(B* CJOJQJ^JaJmHnHphu(B*CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B* CJOJQJ^JaJmHnHphuF======B>>>)?{??@X@]@@@@@@AA"A^AAAAA7$8$H$R7$8$H$^R`AAAAAA4BBBBCCRCCCCCD[D|DDDDEE ER7$8$H$^R`7$8$H$^`7$8$H$ EE&EwFFFFFFGGGGG%G)GHGLGlGpGGGGHHHHIIIIIIIIIIJJJ!J&J(J,J4J7JcJeJuJvJyJ~JJJJJJJKEKLKKKLMMMMAMHMrM۱۱۱(B* CJOJQJ^JaJmHnHphu(B* CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B*CJOJQJ^JaJmHnHphuF E#E$E&E'E(E,EEE$FrFvFwFFFFFFF+G,GNGrGsGGGG 7$8$H$`&d7$8$H$P7$8$H$GGHHfHHHHHHHHH3IIIIIIJJ0J_JyJJJ7$8$H$^`7$8$H$^`7$8$H$JJKEKIKJKKKKKKKKKLbLLLLLLMMM?MAM&d7$8$H$P7$8$H$^`7$8$H$rMvMzMMMMcNNNNNNNNOONOSOO PPPPPPPPPPPPPPP Q$Q5QQQQQQQQQQQQRR1R6RhRRRRRR۱(B* CJOJQJ^JaJmHnHphu(B* CJOJQJ^JaJmHnHphuCJOJQJ^JaJmHnHu(B*CJOJQJ^JaJmHnHphu9AMxMyM~MMMM.N1N^NaNbNgNNNNNNNOIOqOOOOOOO7$8$H$ 7$8$H$`OOP P1P4PgPPPPQ&Q,Q0Q3Q4Q9QQQQQQQ RR-RKReR7$8$H$^`7$8$H$eRRRRRRRR7$8$H$,&P 1h. A!7"7#7$7%SS'Dd+p  S LA.?..\..\..\..\..\nfs.gifb&vNaQ%̽C fm6&Dmn&vNaQ%̽C fm6PNG  IHDR}0PLTE"""fffݪDDDwww333UUUVV2nbKGDH cmPPJCmp0712Om&#IDATxͮ*y@0=fEWd s"{i %@ye yzhs}Zy4ҽe<$XɪſU_qxx=,ʩ}+"s{po Zw0:OQ mtZt»"}ݔΞӽ7MZ$VMMm~tYQ}|q~bxvGNҗ7 wj{&h toeo^zxwwz=UOIv]Hÿ)@)9}? /=9tcsb|4˼}r1:m[ۃf&d#+חTH;P>YV6g_><_/TٳC-q o6ߏ/~b2g=&/͌ ׏}Xov矩[o졷Ϟ-ڜnS;dVM֥|`n_n۫?[۷) m$.mxsoׁ|J[wߓ߮-dw͓ۆoÛ7ΞBzW>'f&dv⍟|`^߼zאG G;۳~ ԇs;o3LS2gw^RkZT"+בwG|sZ%opjpKHm}k1j}u=x1o»xcM͆:ƫ1;>V ě-ܚckoqokrfݦ:ގoaV@%3oE!Ȋ~/{:tw6>WǼݥGhU_2oe-oofN 8)X4vw$Jޖ#xے]@};'R~GdrmVWw^w bJ ] \]+o|8ϭS@-O ܺ9wu6̓KJ"MJtnSC7JK ?3+,ھWM!0E;Tnt 9.AC#_#q0S.#I DޛmF/#V5 UiԹ$: o@. Fq##aދ*D\%)?k8o[.hdpnB;py8'f^ PF|HFQWl[+DP|MSʻx0jdGUo\QWH֊y?BFޜ}I~`6Ҳ<(57B4}n% dwywVWnX)W@l!PȉB7פx j*;'lpxhМ  wg[ v|ִ2Mcr*hC%pNA;e6c]l^ Q+Ȃز Sx1ٮjހ<ރldjW5\o4=&:Ɏ[{\)g d筙aMǘXk q, * 0dh6cy}Tuc4=&^߷wLvZް >X5MWw,wlh:&;-Սw4;l=dW{F ﮂAgh7z˽ @^D&UxWyC>_7 :TxU(V`;5X:_!oo-W+ۢ6>[Xwh ޶'.!b0b>XlUz7[^=Q%>t`lZsv!Pnlx0mx7n>l(7bxO;f?&!:4{E|U("(O;#k(cX,: Y7Ω|;%)l㎷o]l/M3NoɽxߎwIyr {ǛjW{,ªR Fy4`Pub\sGiD/DE/':yuhDG54(UWM ?+O: f!j;t1Y+oODk <"rޣI@F.Z!oC<<Vo ]|C@ث4w鴴8y%2cg$6XuPdGT vdf+y9g*x|'ؿrh'8qTf&{N.(޵1׺a(OHfT~tww;m_o?'i93OӦxn6`ϮyOV~ B+.>&ݵ^.>>2u.>Ϋ; *+{wc pr;ˋ[&ξ|eܶ[OVlv!4jٺ$|oz_knhOL+w] öi^gV=3FEˌcnt|8鍊pMkiN|.B7b}kMطemnS8މd 'ʯFS\pջXk:.~ > }>ThKa zL؋|i8»K FbY5|K=Aw̖>Ua\+Ŗߪf@?'%>6ǣj:ѕ ]Ӭtgִ fts ~wd}bo5.P8;VW, Кm)8%7?B<-ޯt}[o\5]mod邍;@%ߑߛMQ2]ȹ>l?? *Ϋ; J?&@;MօjW0ܓ{ O~jϻMmqhƮ9G+iӵ:N]?þ90Ӫ9/7][#o?JC"ޖolз;ݺ9GKmܓhJ#x[F[oQsf㍲}2{J޾nO">צs4'oRƻ`u+Ohq)wq<v}yI-g7p-aj;lR#yE=0*zy2YG8T O\VnQu1QDʦ}*j'oy;g*+ٟW4u*y+^ṀVxgeip׶aȨԂyC:ҵ#7Xöv죬;yD죞uojG`boj?E({kmι'?N/GY@=r>PyUxUWw^y%yn|g`ޜD` -#dRYta_»:&?* nAK19ؖ]BWxGMG z/  hhs]$oDRoވ[ąwU旈RL}.~J+9py JSu{ \B2Vj ӓ'PC{:y7/JC}ۉ,1VȻ0jB4w=FD4j\nۤ^q$H=c(L-JfcC/~O80?o'beөw(o y|Q |{ %OlGyw=wD[퓙x{7u] |`vw_"&%R |!TD[qfA[ DO({,/ũt+L$o߳S0Q`>QQBdxa3jYUxUWw^yUxժx_*Ϋ=w3PuxUxUWw^yUxU;!_^Zx !_/_xGHG[qxl_xGHkB>(q a9W:QcV􏭹kܮYx;K緦0S Uɻ:b ;tIpx䐟7ֺ#n1,:vY[:uqȟ6Cݭͅ  NvI܋=-ӅJaXzO+k,}\~Cgy*x+ɫ.HMpl5Vie+RU4*JW+,Q~Ȕg'{YyPqsZDy]}72ot+ =*i\X{jwûV9Mw\N\e=DV @zTHJP- Y_DxO-6%>AnzސVPP\T RȗF *b {B-;g*ÝTx*vTL0 8Hw J۫t4xAm(4nIWȻn([(M] Z&ovV[&FTya!Z/o&+ qp]a;Qx֎\0Bd~q»߾, qy"z; A[xD|w&]G* zܓoV6W]xϥMIGFӁHp\VRW>Rx#x1f⭤UF5>{D9NJs~17MϪT0?j5*s4oz>ؕ[ąu\ ļ_f-O^lл)R*CB{ XG.ݜEVTfo6Z-o-x+ v'B+>[ .ms5,݊"Tn)^P6vռY{N 'Ϋ; *Ϋ; *Ϋ;{n:^X]xO{r MM)Y2+YnvZey].[j0o(P69>d(onqʓMRcs*ެ,O0 ꊛٰYseC{>PmsjVm*79>uм79>fЛUx+Κa7kC o&LJެM)YRx69>fmr|H {&OY>?w=r^xIZoeYy^[-/ʓ[ _asYxONirYxO'!Ċ9dbv{j6 $*ƳvZoά; *Ϋ;:^F`DӈszÓyЖw~ c_!~JevGNҗ~t^?NCs>oS_T>2ݝ޾GgG%G<|v|%E-{loKI']=@ޛ O737c;2%~wCx+W8@WQqggWOm58Of9l {_xlvJ(UG%Ci6N4]^'(@ÅX<mF;Mە_*[l!v.+IM7i~3ƻ]SziXֲ< @Dq^I"$/AyNoJ WE d"\5oŗn+c]4lUsm(}k/v(FwH{w.?? *mWUèh /Q8mzl-7;Usn'`78uLPu"؛C=MM{{m854\5}E}aENS ž;͛Ļ)NQޙ)|\@-9^O+G6TRiQkk _5AgR-a : o c٭TxUWw^iv0Rcǐ:%7u0}M xCd. JxtY]V ߵ1TXoovxx{!/c F?%vlX1a']r剮[ޗ5rs*RU >ot4v59oPYFq9yt{(x{1J (Q\0oPG 7oӋ'nؕlt+ry{wE -=!}ׯ.ٶV*(. X_K6ByWnhZo<P˓K+mDNۡ}bnhZ!YUxUWw^yUxU;>yTֿwlq!J_&/0qAIh(UWyh:R7ٿ(=yأ;-riej=zWw^y5o[Ǎ ݊{k弡nyn7;zwt']#n[ۍFch:uk$A [ۍ-./ORakwqVO4͓a8VXS)|*:SnܹyLpㄦ.~JL)xGakqe4w*C㰵ݸN8PUh,ޙ54ל|wn_;&r 1U'Io E^}KʻSxϭ; :N ] yÎchsŪBC6㧘^#c2تBciC{-j{Yp^`{Jkl Lv8V?iE@p]1~OQ iUzڿy4٧"5hmy{\V8נ@'Px7h*Ϋ; *Ϋ; *j/@,* , ~=zgXQ]xOĻ( J* IENDB` i8@8 NormalCJ_HaJmH sH tH T@T Heading 2$$+@&^+`CJ$aJmHnHuF2F Heading 3dd@&[$\$5CJ\aJHBH Heading 4dd@&[$\$5B*\ph<A@< Default Paragraph FontXX Number List  & F%B*CJOJQJ_HmH phsH tH PP BulletSeminar & FdCJKHOJQJaJ^^ BulletTIJ% & F h88d^8CJKHOJQJaJNC"NBody Text Indent$:`:a$ mHnHudd Heading 3.H3$$hd x<^hCJ,OJQJ_HmH sH tH \B\Code!d%d O ^CJKHOJQJaJmHnHu,AR, CodeInline<^b^ CodeInlineTrailer^CJOJQJ_HmH sH tH :^r: Normal (Web)dd[$\$:b@: HTML CodeCJOJPJQJ^JaJ<B< Body Text $a$ mHnHu"W@" Strong5\&X@& Emphasis6].U@. Hyperlink >*B*phe HTML Preformatted7 2( Px 4 #\'*.25@9CJOJPJQJ^JaJ44 paradd[$\$ B*phM&PQ.be \N _bZoc~O0  < M A 1 ' 4 %x36>N Om*./Ki:<qQ#(ADZm"gl T',UX}16RdgRr(O;ns.2R(o>$ A E F i q *!K!O!P!S!T!Y!!!!!!>"b"~""""""" # #/#L#T######E$$$%Q%U%}%%%%&&@&&&& '@'['v'''''''(+(0(R(U(k((((((((!)$)Y)a)x))))))))))))D***(+,+-+E+f+++++++,,j,,,, -+-,-1-y----G.].`....../P////000W0v0w000)1m111111-2g22233T33334S44444453575:5;5@55556u6z66667&7s777/808U8x8y8888888B999):{::;X;];;;;;;<<"<^<<<<<<<<<<4====>>R>>>>>?[?|????@@ @#@$@&@'@(@,@@@$ArAvAwAAAAAAA+B,BNBrBsBBBBBCCfCCCCCCCCC3DDDDDDEE0E_EyEEEEFEFIFJFFFFFFFFFGbGGGGGGHHH?HAHxHyH~HHHH.I1I^IaIbIgIIIIIIIJIJqJJJJJJJJK K1K4KgKKKKL&L,L0L3L4L9LLLLLLL MM-MKMeMMMMMMMM000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000^T$4*1v< ErMR+1469=@CGb KX!i% ( ,x.j159=A EGJAMOeRR,./023578:;<>?ABDEFHIJR- _Toc375545495 _Toc408018768MQQMFFMFFMFF?H?HAHAHxHxHaIaIIIJJNJNJnJnJJJfKgKKKLL3L3LLL1M1MIMIMM Star Gruhtar|C:\Documents and Settings\Administrator\Application Data\Microsoft\Word\AutoRecovery save of InetJava-1.9-Chat-Client-Server Star GruhtarYC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\new\InetJava-1.9-Chat-Client-Server.doc Star Gruhtar|C:\Documents and Settings\Administrator\Application Data\Microsoft\Word\AutoRecovery save of InetJava-1.9-Chat-Client-Server Star Gruhtar|C:\Documents and Settings\Administrator\Application Data\Microsoft\Word\AutoRecovery save of InetJava-1.9-Chat-Client-Server Star GruhtarYC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\new\InetJava-1.9-Chat-Client-Server.doc Star GruhtarZC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\InetJava-1.10-Forward-Server-Example.doc Star GruhtarZC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\InetJava-1.10-Forward-Server-Example.doc Star GruhtarC:\Documents and Settings\Administrator\Application Data\Microsoft\Word\AutoRecovery save of InetJava-1.10-Forward-Server-Example Star GruhtarZC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\InetJava-1.10-Forward-Server-Example.doc Star GruhtarZC:\NAKOV\PROJECTS\InetJava\lectures\part1_sockets\InetJava-1.10-Forward-Server-Example.doc|}~,޸h.| @n`#dbʤ.iy8 bw4^.Q'«h$@  xg`  #3  o \ԐZAg )g)3p8qX W &q޷l% %;   c,?20 1z Qt .AT rl UX  H ]-- :j;u OJ ?F   4gC  k\T  < " &## ~D% LM% n& ) ) +*q޷ *^|U+jV+ !.Nm_xa2 ?3q޷o 4,e6s*5  6q޷>CM7 r*8 \#d8 Q8q޷8q޷69ޞi9 r\B PBl[ xC ByCL0C m D tD I-*E Eq޷gECFHG`J XJ _J s`Mq޷ NR j96r~N *N \O2T$$7ROES 9U NwV -UWq޷F6Xq޷HYq޷IY T4Yq޷c7Y eZ @<\ VS^ S` A` 41`z鈥b Cb j!b֩d&~c #~4dq޷8d 1fN vmgR6Vg eqhq޷)h\$!h R+i,U6jT$`mW kvW3l GlrwC/lh>m(m47Em XGm ^n 6(n MoL`&dp b.p l**q j#r ==s  t F tqv,v ~mw OJx  } (C~ =~ ^`.^`.88^8`.^`. ^`OJQJo( ^`OJQJo( 88^8`OJQJo( ^`OJQJo(hh^h`. hh^h`OJQJo(*^`.^`.p^p`.@ ^@ `.^`.^`.^`.^`.@hp^p`. hh^h`OJQJo(vh ^`OJQJo(h pp^p`OJQJo(oh @ @ ^@ `OJQJo(h ^`OJQJo(h ^`OJQJo(oh ^`OJQJo(h ^`OJQJo(h PP^P`OJQJo(oh   ^ `OJQJo( hh^h`OJQJo(v^`.^`CJOJQJo(opp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.hh^h`.hh^h`. h8^h`OJQJo( hh^h`OJQJo(v@hp^p`. ^`OJQJo( hh^h`OJQJo(vhh^h`.@h^`56>*CJOJQJo(.  hh^h`OJQJo(vhh^h`.hh^h`.@hp^p`. hh^h`OJQJo(vhh^h`.hh^h`.hh^h`.hh^h`.hh^h`.hh^h`. hh^h`OJQJo( hh^h`OJQJo(vhh^h`. hh^h`OJQJo(vhh^h`.h^`.h^`.hpLp^p`L.h@ @ ^@ `.h^`.hL^`L.h^`.h^`.hPLP^P`L.hh^h`. hh^h`OJQJo(hh^h`.hh^h`.hh^h`. hh^h`OJQJo(hh^h`. hh^h`OJQJo(vhh^h`.@h^`56>*CJOJQJo(. @hp^p`.@hp^p`.hh^h`.@hp^p`. hh^h`OJQJo(v@h^`56>*CJOJQJo(. @hp^p`.hh^h`.@h^`56>*CJOJQJo(. hh^h`. hh^h`OJQJo( hh^h`OJQJo(@h^`56>*CJOJQJo(. @h^`56>*CJOJQJo(. x(x^x`(56>*CJ o(. hh^h`.hh^h`.hh^h`B*CJOJQJo( hh^h`OJQJo(v@hp^p`. hh^h`OJQJo(hh^h`. hh^h`OJQJo(hh^h`.@h^`56>*CJOJQJo(. @hp^p`.@hp^p`. hh^h`OJQJo(vhh^h`.hh^h`.@h^`56>*CJOJQJo(. @hp^p`.hh^h`.hh^h`.@hp^p`.@hp^p`.hh^h`. hh^h`OJQJo(hh^h`.@h^`56>*CJOJQJo(. @h^`56>*CJOJQJo(. @h^`56>*CJOJQJo(. hh^h`.@h^`56>*CJOJQJo(.  hh^h`OJQJo(vhh^h`. hh^h`OJQJo(v hh^h`OJQJo(v hh^h`OJQJo( hh^h`OJQJo(@hp^p`.hh^h`.hh^h`.@hp^p`. hh^h`OJQJo(v@h^`56>*CJOJQJo(. hh^h`.@hp^p`.@hp^p`.hh^h`.@h^`56>*CJOJQJo(. @hp^p`.hh^h`.^`CJOJQJo(^`CJOJQJo(opp^p`CJOJQJo(@ @ ^@ `CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(^`CJOJQJo(PP^P`CJOJQJo(h ^`OJQJo(h pp^p`OJQJo(oh @ @ ^@ `OJQJo(h ^`OJQJo(h ^`OJQJo(oh ^`OJQJo(h ^`OJQJo(h PP^P`OJQJo(oh   ^ `OJQJo(@hp^p`. hh^h`OJQJo(vhh^h`B*CJOJQJo(hh^h`B*CJOJQJo(@hp^p`.hh^h`. hh^h`OJQJo( hh^h`OJQJo(vhh^h`.@hp^p`.hh^h`.hh^h`.hh^h`.hh^h`. hh^h`OJQJo(v hh^h`OJQJo(@hp^p`.@hp^p`.hh^h`.hh^h`.hh^h`. hh^h`OJQJo(vhh^h`.hh^h`.<F tF tww69eqh+*++Pvmgvmg * *E!.!.Xm(mm(ms`MqvqvMoMo`)h)h 6HY41`41`T4YgEgEh#~4d\O\OF6X N N|mW kmW kԴ8?3$7R$7R,1f1fo 4o 4ܵ-UWFHGFHG4Q8ByCByCj!bj!b䶤c,c,<rlu~}|췤6(neZgC Vg !h)s*50C=~]--dpm D1z6r~N~D%NwV&## H.ATI-*E&7Em< "UXCb?FXJ%;r\BQt~mw_Jb8di9OES.690IYn&,vl**qOJxW*N<V+(C~20l%c7YAg3l xCOJ>CM7b.pS`#d8g)3j#rtDXGm tA`9ULM%k\T #3 ` `J^nxa2&~c }==sqX)VS^h$@@<\:r*8/lGlo PBR+i'6j   H @ P^`POJQJo( @hp^p`. @hp^p`.\ @hp^p`. @hp^p`.  @hp^p`.d @hp^p`. @hp^p`. @hp^p`.l @hp^p`.IJ @hp^p`. @hp^p`.t @hp^p`.̳ @hp^p`.$ @h p^p`OJQJo( @hp^p`.ത @hp^p`.8 @hp^p`. @hp^p`.赤 @hp^p`.@ @hp^p`. @hp^p`. @hp^p`.H @hp^p`. @hp^p`.H @h h^h`OJQJo( @h ^`OJQJo(         q-H:~S 6F8lL*8B@Y$         wxԴ*X]D,uoVp$         @FFXqFFMPP @UnknownGz Times New Roman5Symbol3& z Arial?5 z Courier NewcCarmina Md BTTimes New RomanaBCalligraph421 BTCourier New;WingdingsE AmerType Md BT"h6cFgcF/< @ !779r0dN2Q%Internet Programming with Java Course Star Gruhtar Star GruhtarOh+'0 0< X d p|&Internet Programming with Java Courset nte Star Gruhtarramtartar Normal.dotr Star Gruhtarram5arMicrosoft Word 9.0g@ِ@T@GҺ<  @՜.+,D՜.+,X hp   Magic Team N &Internet Programming with Java Course Title 8@ _PID_HLINKSAhS22..\..\..\..\..\nfs.gif  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~Root Entry FJҺData L'1Table`WordDocument.SummaryInformation(DocumentSummaryInformation8CompObjjObjectPoolJҺJҺ  FMicrosoft Word Document MSWordDocWord.Document.89q