Vous êtes sur la page 1sur 32

Java Socket

Programming
Examples
Although most programmers probably do network programming using a nice library
with high-level application protocol (such as HTTP) support built-in, it's still useful to
have an understanding of how to code at the socket level. Here are a few complete
examples you can compile and run.

Overview
We will look at four network applications, written completely from scratch in
Java. We will see that we can write these programs without any knowledge
of the technologies under the hood (which include operating system
resources, routing between networks, address lookup, physical
transmission media, etc.)
Each of these applications use the client-server paradigm, which is roughly
1. One program, called the server blocks waiting for a client to connect
to it
2. A client connects
3. The server and the client exchange information until they're done
4. The client and the server both close their connection
The only pieces of background information you need are:

Hosts have ports, numbered from 0-65535. Servers listen on a port.


Some port numbers are reserved so you can't use them when you
write your own server.
Multiple clients can be communicating with a server on a given port.
Each client connection is assigned a separate socket on that port.
Client applications get a port and a socket on the client machine
when they connect successfully with a server.
The four applications are
A trivial date server and client, illustrating simple one-way
communication. The server sends data to the client only.
A capitalize server and client, illustrating two-way communication.
Since the dialog between the client and server can comprise an
unbounded number of messages back and forth, the server
is threaded to service multiple clients efficiently.
A two-player tic tac toe game, illustrating a server that needs to keep
track of the state of a game, and inform each client of it, so they can
each update their own displays.
A multi-user chat application, in which a server must broadcast
messages to all of its clients.

A Date Server and Client


The server
DateServer.java
packageedu.lmu.cs.networking;
importjava.io.IOException;
importjava.io.PrintWriter;

importjava.net.ServerSocket;
importjava.net.Socket;
importjava.util.Date;
/**
*ATCPserverthatrunsonport9090.Whenaclient
connects,it
*sendstheclientthecurrentdateandtime,thenclosesthe
*connectionwiththatclient.Arguablyjustaboutthe
simplest
*serveryoucanwrite.
*/
publicclassDateServer{
/**
*Runstheserver.
*/
publicstaticvoidmain(String[]args)throwsIOException
{
ServerSocketlistener=newServerSocket(9090);
try{
while(true){
Socketsocket=listener.accept();
try{
PrintWriterout=
new
PrintWriter(socket.getOutputStream(),true);
out.println(newDate().toString());
}finally{
socket.close();
}
}
}
finally{
listener.close();
}
}
}

The client

DateClient.java
packageedu.lmu.cs.networking;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.net.Socket;
importjavax.swing.JOptionPane;
/**
*Trivialclientforthedateserver.
*/
publicclassDateClient{
/**
*Runstheclientasanapplication.Firstitdisplaysa
dialog
*boxaskingfortheIPaddressorhostnameofahost
running
*thedateserver,thenconnectstoitanddisplaysthe
datethat
*itserves.
*/
publicstaticvoidmain(String[]args)throwsIOException
{
StringserverAddress=JOptionPane.showInputDialog(
"EnterIPAddressofamachinethatis\n"+
"runningthedateserviceonport9090:");
Sockets=newSocket(serverAddress,9090);
BufferedReaderinput=
newBufferedReader(new
InputStreamReader(s.getInputStream()));
Stringanswer=input.readLine();
JOptionPane.showMessageDialog(null,answer);
System.exit(0);
}
}

You can also test the server with telnet.

A Capitalization Server and


Client
The server
CapitalizeServer.java
packageedu.lmu.cs.networking;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*Aserverprogramwhichacceptsrequestsfromclientsto
*capitalizestrings.Whenclientsconnect,anewthreadis
*startedtohandleaninteractivedialoginwhichtheclient
*sendsinastringandtheserverthreadsendsbackthe
*capitalizedversionofthestring.
*
*Theprogramisrunsinaninfiniteloop,soshutdownin
platform
*dependent.Ifyouranitfromaconsolewindowwiththe
"java"
*interpreter,Ctrl+Cgenerallywillshutitdown.
*/
publicclassCapitalizeServer{
/**
*Applicationmethodtoruntheserverrunsinan
infiniteloop
*listeningonport9898.Whenaconnectionis
requested,it

*spawnsanewthreadtodotheservicingandimmediately
returns
*tolistening.Theserverkeepsauniqueclientnumber
foreach
*clientthatconnectsjusttoshowinterestinglogging
*messages.Itiscertainlynotnecessarytodothis.
*/
publicstaticvoidmain(String[]args)throwsException{
System.out.println("Thecapitalizationserveris
running.");
intclientNumber=0;
ServerSocketlistener=newServerSocket(9898);
try{
while(true){
newCapitalizer(listener.accept(),
clientNumber++).start();
}
}finally{
listener.close();
}
}
/**
*Aprivatethreadtohandlecapitalizationrequestsona
particular
*socket.Theclientterminatesthedialoguebysending
asingleline
*containingonlyaperiod.
*/
privatestaticclassCapitalizerextendsThread{
privateSocketsocket;
privateintclientNumber;
publicCapitalizer(Socketsocket,intclientNumber){
this.socket=socket;
this.clientNumber=clientNumber;
log("Newconnectionwithclient#"+clientNumber
+"at"+socket);
}

/**
*Servicesthisthread'sclientbyfirstsendingthe
*clientawelcomemessagethenrepeatedlyreading
strings
*andsendingbackthecapitalizedversionofthe
string.
*/
publicvoidrun(){
try{
//Decoratethestreamssowecansend
characters
//andnotjustbytes.Ensureoutputis
flushed
//aftereverynewline.
BufferedReaderin=newBufferedReader(
new
InputStreamReader(socket.getInputStream()));
PrintWriterout=
newPrintWriter(socket.getOutputStream(),
true);
//Sendawelcomemessagetotheclient.
out.println("Hello,youareclient#"+
clientNumber+".");
out.println("Enteralinewithonlyaperiod
toquit\n");
//Getmessagesfromtheclient,linebyline;
returnthem
//capitalized
while(true){
Stringinput=in.readLine();
if(input==null||input.equals(".")){
break;
}
out.println(input.toUpperCase());
}
}catch(IOExceptione){
log("Errorhandlingclient#"+clientNumber+

":"+e);
}finally{
try{
socket.close();
}catch(IOExceptione){
log("Couldn'tcloseasocket,what'sgoing
on?");
}
log("Connectionwithclient#"+clientNumber
+"closed");
}
}
/**
*Logsasimplemessage.Inthiscasewejustwrite
the
*messagetotheserverapplicationsstandardoutput.
*/
privatevoidlog(Stringmessage){
System.out.println(message);
}
}
}

The client
CapitalizeClient.java
packageedu.lmu.cs.networking;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.Socket;
importjavax.swing.JFrame;

importjavax.swing.JOptionPane;
importjavax.swing.JScrollPane;
importjavax.swing.JTextArea;
importjavax.swing.JTextField;
/**
*AsimpleSwingbasedclientforthecapitalizationserver.
*Ithasamainframewindowwithatextfieldforentering
*stringsandatextareatoseetheresultsofcapitalizing
*them.
*/
publicclassCapitalizeClient{
privateBufferedReaderin;
privatePrintWriterout;
privateJFrameframe=newJFrame("CapitalizeClient");
privateJTextFielddataField=newJTextField(40);
privateJTextAreamessageArea=newJTextArea(8,60);
/**
*ConstructstheclientbylayingouttheGUIand
registeringa
*listenerwiththetextfieldsothatpressingEnterin
the
*listenersendsthetextfieldcontentstotheserver.
*/
publicCapitalizeClient(){
//LayoutGUI
messageArea.setEditable(false);
frame.getContentPane().add(dataField,"North");
frame.getContentPane().add(new
JScrollPane(messageArea),"Center");
//AddListeners
dataField.addActionListener(newActionListener(){
/**
*Respondstopressingtheenterkeyinthe
textfield
*bysendingthecontentsofthetextfieldto

the
*serveranddisplayingtheresponsefromthe
server
*inthetextarea.Iftheresponseis"."we
exit
*thewholeapplication,whichclosesall
sockets,
*streamsandwindows.
*/
publicvoidactionPerformed(ActionEvente){
out.println(dataField.getText());
Stringresponse;
try{
response=in.readLine();
if(response==null||
response.equals("")){
System.exit(0);
}
}catch(IOExceptionex){
response="Error:"+ex;
}
messageArea.append(response+"\n");
dataField.selectAll();
}
});
}
/**
*Implementstheconnectionlogicbypromptingtheend
userfor
*theserver'sIPaddress,connecting,settingup
streams,and
*consumingthewelcomemessagesfromtheserver.The
Capitalizer
*protocolsaysthattheserversendsthreelinesoftext
tothe
*clientimmediatelyafterestablishingaconnection.
*/
publicvoidconnectToServer()throwsIOException{

//Gettheserveraddressfromadialogbox.
StringserverAddress=JOptionPane.showInputDialog(
frame,
"EnterIPAddressoftheServer:",
"WelcometotheCapitalizationProgram",
JOptionPane.QUESTION_MESSAGE);
//Makeconnectionandinitializestreams
Socketsocket=newSocket(serverAddress,9898);
in=newBufferedReader(
new
InputStreamReader(socket.getInputStream()));
out=newPrintWriter(socket.getOutputStream(),true);
//Consumetheinitialwelcomingmessagesfromthe
server
for(inti=0;i<3;i++){
messageArea.append(in.readLine()+"\n");
}
}
/**
*Runstheclientapplication.
*/
publicstaticvoidmain(String[]args)throwsException{
CapitalizeClientclient=newCapitalizeClient();

client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.pack();
client.frame.setVisible(true);
client.connectToServer();
}
}

A Two-Player Networked TicTac-Toe Game


The server

TicTacToeServer.java
packageedu.lmu.cs.networking;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*Aserverforanetworkmultiplayertictactoegame.
Modifiedand
*extendedfromtheclasspresentedinDeitelandDeitel
"JavaHowto
*Program"book.Imadeabunchofenhancementsandrewrote
largesections
*ofthecode.Themainchangeisinsteadofpassing*data*
betweenthe
*clientandserver,ImadeaTTTP(tictactoeprotocol)
whichistotally
*plaintext,soyoucantestthegamewithTelnet(alwaysa
goodidea.)
*ThestringsthataresentinTTTPare:
*
*Client>ServerServer>Client
*
*MOVE<n>(0<=n<=8)WELCOME<char>(charin{X,
O})
*QUITVALID_MOVE
*OTHER_PLAYER_MOVED<n>
*VICTORY
*DEFEAT
*TIE
*MESSAGE<text>
*
*Asecondchangeisthatitallowsanunlimitednumberof
pairsof
*playerstoplay.

*/
publicclassTicTacToeServer{
/**
*Runstheapplication.Pairsupclientsthatconnect.
*/
publicstaticvoidmain(String[]args)throwsException{
ServerSocketlistener=newServerSocket(8901);
System.out.println("TicTacToeServerisRunning");
try{
while(true){
Gamegame=newGame();
Game.PlayerplayerX=game.new
Player(listener.accept(),'X');
Game.PlayerplayerO=game.new
Player(listener.accept(),'O');
playerX.setOpponent(playerO);
playerO.setOpponent(playerX);
game.currentPlayer=playerX;
playerX.start();
playerO.start();
}
}finally{
listener.close();
}
}
}
/**
*Atwoplayergame.
*/
classGame{
/**
*Aboardhasninesquares.Eachsquareiseither
unownedor
*itisownedbyaplayer.Soweuseasimplearrayof
player
*references.Ifnull,thecorrespondingsquareis
unowned,

*otherwisethearraycellstoresareferencetothe
playerthat
*ownsit.
*/
privatePlayer[]board={
null,null,null,
null,null,null,
null,null,null};
/**
*Thecurrentplayer.
*/
PlayercurrentPlayer;
/**
*Returnswhetherthecurrentstateoftheboardissuch
thatone
*oftheplayersisawinner.
*/
publicbooleanhasWinner(){
return
(board[0]!=null&&board[0]==board[1]&&
board[0]==board[2])
||(board[3]!=null&&board[3]==board[4]&&
board[3]==board[5])
||(board[6]!=null&&board[6]==board[7]&&
board[6]==board[8])
||(board[0]!=null&&board[0]==board[3]&&
board[0]==board[6])
||(board[1]!=null&&board[1]==board[4]&&
board[1]==board[7])
||(board[2]!=null&&board[2]==board[5]&&
board[2]==board[8])
||(board[0]!=null&&board[0]==board[4]&&
board[0]==board[8])
||(board[2]!=null&&board[2]==board[4]&&
board[2]==board[6]);
}
/**

*Returnswhethertherearenomoreemptysquares.
*/
publicbooleanboardFilledUp(){
for(inti=0;i<board.length;i++){
if(board[i]==null){
returnfalse;
}
}
returntrue;
}
/**
*Calledbytheplayerthreadswhenaplayertriesto
makea
*move.Thismethodcheckstoseeifthemoveislegal:
that
*is,theplayerrequestingthemovemustbethecurrent
player
*andthesquareinwhichsheistryingtomovemustnot
already
*beoccupied.Ifthemoveislegalthegamestateis
updated
*(thesquareissetandthenextplayerbecomescurrent)
and
*theotherplayerisnotifiedofthemovesoitcan
updateits
*client.
*/
publicsynchronizedbooleanlegalMove(intlocation,Player
player){
if(player==currentPlayer&&board[location]==
null){
board[location]=currentPlayer;
currentPlayer=currentPlayer.opponent;
currentPlayer.otherPlayerMoved(location);
returntrue;
}
returnfalse;
}

/**
*Theclassforthehelperthreadsinthismultithreaded
server
*application.APlayerisidentifiedbyacharacter
mark
*whichiseither'X'or'O'.Forcommunicationwiththe
*clienttheplayerhasasocketwithitsinputand
output
*streams.Sinceonlytextisbeingcommunicatedweuse
a
*readerandawriter.
*/
classPlayerextendsThread{
charmark;
Playeropponent;
Socketsocket;
BufferedReaderinput;
PrintWriteroutput;
/**
*Constructsahandlerthreadforagivensocketand
mark
*initializesthestreamfields,displaysthefirst
two
*welcomingmessages.
*/
publicPlayer(Socketsocket,charmark){
this.socket=socket;
this.mark=mark;
try{
input=newBufferedReader(
new
InputStreamReader(socket.getInputStream()));
output=new
PrintWriter(socket.getOutputStream(),true);
output.println("WELCOME"+mark);
output.println("MESSAGEWaitingforopponent
toconnect");
}catch(IOExceptione){
System.out.println("Playerdied:"+e);

}
}
/**
*Acceptsnotificationofwhotheopponentis.
*/
publicvoidsetOpponent(Playeropponent){
this.opponent=opponent;
}
/**
*HandlestheotherPlayerMovedmessage.
*/
publicvoidotherPlayerMoved(intlocation){
output.println("OPPONENT_MOVED"+location);
output.println(
hasWinner()?"DEFEAT":boardFilledUp()?
"TIE":"");
}
/**
*Therunmethodofthisthread.
*/
publicvoidrun(){
try{
//Thethreadisonlystartedaftereveryone
connects.
output.println("MESSAGEAllplayers
connected");
//Tellthefirstplayerthatitisherturn.
if(mark=='X'){
output.println("MESSAGEYourmove");
}
//Repeatedlygetcommandsfromtheclientand
processthem.
while(true){
Stringcommand=input.readLine();
if(command.startsWith("MOVE")){

intlocation=
Integer.parseInt(command.substring(5));
if(legalMove(location,this)){
output.println("VALID_MOVE");
output.println(hasWinner()?
"VICTORY"
:boardFilledUp()?
"TIE"
:"");
}else{
output.println("MESSAGE?");
}
}elseif(command.startsWith("QUIT")){
return;
}
}
}catch(IOExceptione){
System.out.println("Playerdied:"+e);
}finally{
try{socket.close();}catch(IOExceptione){}
}
}
}
}

The client
TicTacToeClient.java
packageedu.lmu.cs.networking;
importjava.awt.Color;
importjava.awt.GridLayout;
importjava.awt.event.MouseAdapter;
importjava.awt.event.MouseEvent;
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.Socket;

importjavax.swing.Icon;
importjavax.swing.ImageIcon;
importjavax.swing.JFrame;
importjavax.swing.JLabel;
importjavax.swing.JOptionPane;
importjavax.swing.JPanel;
/**
*AclientfortheTicTacToegame,modifiedandextendedfrom
the
*classpresentedinDeitelandDeitel"JavaHowtoProgram"
book.
*Imadeabunchofenhancementsandrewrotelargesections
ofthe
*code.InparticularIcreatedtheTTTP(TicTacToe
Protocol)
*whichisentirelytextbased.Herearethestringsthat
aresent:
*
*Client>ServerServer>Client
*
*MOVE<n>(0<=n<=8)WELCOME<char>(charin{X,
O})
*QUITVALID_MOVE
*OTHER_PLAYER_MOVED<n>
*VICTORY
*DEFEAT
*TIE
*MESSAGE<text>
*
*/
publicclassTicTacToeClient{
privateJFrameframe=newJFrame("TicTacToe");
privateJLabelmessageLabel=newJLabel("");
privateImageIconicon;
privateImageIconopponentIcon;
privateSquare[]board=newSquare[9];

privateSquarecurrentSquare;
privatestaticintPORT=8901;
privateSocketsocket;
privateBufferedReaderin;
privatePrintWriterout;
/**
*Constructstheclientbyconnectingtoaserver,laying
outthe
*GUIandregisteringGUIlisteners.
*/
publicTicTacToeClient(StringserverAddress)throws
Exception{
//Setupnetworking
socket=newSocket(serverAddress,PORT);
in=newBufferedReader(newInputStreamReader(
socket.getInputStream()));
out=newPrintWriter(socket.getOutputStream(),true);
//LayoutGUI
messageLabel.setBackground(Color.lightGray);
frame.getContentPane().add(messageLabel,"South");
JPanelboardPanel=newJPanel();
boardPanel.setBackground(Color.black);
boardPanel.setLayout(newGridLayout(3,3,2,2));
for(inti=0;i<board.length;i++){
finalintj=i;
board[i]=newSquare();
board[i].addMouseListener(newMouseAdapter(){
publicvoidmousePressed(MouseEvente){
currentSquare=board[j];
out.println("MOVE"+j);}});
boardPanel.add(board[i]);
}
frame.getContentPane().add(boardPanel,"Center");
}

/**
*Themainthreadoftheclientwilllistenformessages
*fromtheserver.Thefirstmessagewillbea"WELCOME"
*messageinwhichwereceiveourmark.Thenwegointo
a
*looplisteningfor"VALID_MOVE","OPPONENT_MOVED",
"VICTORY",
*"DEFEAT","TIE","OPPONENT_QUITor"MESSAGE"messages,
*andhandlingeachmessageappropriately.The
"VICTORY",
*"DEFEAT"and"TIE"asktheuserwhetherornottoplay
*anothergame.Iftheanswerisno,theloopisexited
and
*theserverissenta"QUIT"message.Ifan
OPPONENT_QUIT
*messageisreceviedthentheloopwillexitandthe
server
*willbesenta"QUIT"messagealso.
*/
publicvoidplay()throwsException{
Stringresponse;
try{
response=in.readLine();
if(response.startsWith("WELCOME")){
charmark=response.charAt(8);
icon=newImageIcon(mark=='X'?"x.gif":
"o.gif");
opponentIcon=newImageIcon(mark=='X'?
"o.gif":"x.gif");
frame.setTitle("TicTacToePlayer"+
mark);
}
while(true){
response=in.readLine();
if(response.startsWith("VALID_MOVE")){
messageLabel.setText("Validmove,please
wait");
currentSquare.setIcon(icon);
currentSquare.repaint();
}elseif

(response.startsWith("OPPONENT_MOVED")){
intloc=
Integer.parseInt(response.substring(15));
board[loc].setIcon(opponentIcon);
board[loc].repaint();
messageLabel.setText("Opponentmoved,your
turn");
}elseif(response.startsWith("VICTORY")){
messageLabel.setText("Youwin");
break;
}elseif(response.startsWith("DEFEAT")){
messageLabel.setText("Youlose");
break;
}elseif(response.startsWith("TIE")){
messageLabel.setText("Youtied");
break;
}elseif(response.startsWith("MESSAGE")){

messageLabel.setText(response.substring(8));
}
}
out.println("QUIT");
}
finally{
socket.close();
}
}
privatebooleanwantsToPlayAgain(){
intresponse=JOptionPane.showConfirmDialog(frame,
"Wanttoplayagain?",
"TicTacToeisFunFunFun",
JOptionPane.YES_NO_OPTION);
frame.dispose();
returnresponse==JOptionPane.YES_OPTION;
}
/**
*Graphicalsquareintheclientwindow.Eachsquareis
*awhitepanelcontaining.AclientcallssetIcon()to

fill
*itwithanIcon,presumablyanXorO.
*/
staticclassSquareextendsJPanel{
JLabellabel=newJLabel((Icon)null);
publicSquare(){
setBackground(Color.white);
add(label);
}
publicvoidsetIcon(Iconicon){
label.setIcon(icon);
}
}
/**
*Runstheclientasanapplication.
*/
publicstaticvoidmain(String[]args)throwsException{
while(true){
StringserverAddress=(args.length==0)?
"localhost":args[1];
TicTacToeClientclient=new
TicTacToeClient(serverAddress);

client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setSize(240,160);
client.frame.setVisible(true);
client.frame.setResizable(false);
client.play();
if(!client.wantsToPlayAgain()){
break;
}
}
}
}

A Multi-User Chat Application

The server
ChatServer.java
packageedu.lmu.cs.networking;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
importjava.util.HashSet;
/**
*Amultithreadedchatroomserver.Whenaclientconnects
the
*serverrequestsascreennamebysendingtheclientthe
*text"SUBMITNAME",andkeepsrequestinganameuntil
*auniqueoneisreceived.Afteraclientsubmitsaunique
*name,theserveracknowledgeswith"NAMEACCEPTED".Then
*allmessagesfromthatclientwillbebroadcasttoall
other
*clientsthathavesubmittedauniquescreenname.The
*broadcastmessagesareprefixedwith"MESSAGE".
*
*Becausethisisjustateachingexampletoillustratea
simple
*chatserver,thereareafewfeaturesthathavebeenleft
out.
*Twoareveryusefulandbelonginproductioncode:
*
*1.Theprotocolshouldbeenhancedsothattheclient
can
*sendcleandisconnectmessagestotheserver.
*
*2.Theservershoulddosomelogging.
*/
publicclassChatServer{

/**
*Theportthattheserverlistenson.
*/
privatestaticfinalintPORT=9001;
/**
*Thesetofallnamesofclientsinthechatroom.
Maintained
*sothatwecancheckthatnewclientsarenot
registeringname
*alreadyinuse.
*/
privatestaticHashSet<String>names=new
HashSet<String>();
/**
*Thesetofalltheprintwritersforalltheclients.
This
*setiskeptsowecaneasilybroadcastmessages.
*/
privatestaticHashSet<PrintWriter>writers=new
HashSet<PrintWriter>();
/**
*Theappplicationmainmethod,whichjustlistensona
portand
*spawnshandlerthreads.
*/
publicstaticvoidmain(String[]args)throwsException{
System.out.println("Thechatserverisrunning.");
ServerSocketlistener=newServerSocket(PORT);
try{
while(true){
newHandler(listener.accept()).start();
}
}finally{
listener.close();
}
}

/**
*Ahandlerthreadclass.Handlersarespawnedfromthe
listening
*loopandareresponsibleforadealingwithasingle
client
*andbroadcastingitsmessages.
*/
privatestaticclassHandlerextendsThread{
privateStringname;
privateSocketsocket;
privateBufferedReaderin;
privatePrintWriterout;
/**
*Constructsahandlerthread,squirrelingawaythe
socket.
*Alltheinterestingworkisdoneintherunmethod.
*/
publicHandler(Socketsocket){
this.socket=socket;
}
/**
*Servicesthisthread'sclientbyrepeatedly
requestinga
*screennameuntilauniqueonehasbeensubmitted,
then
*acknowledgesthenameandregisterstheoutput
streamfor
*theclientinaglobalset,thenrepeatedlygets
inputsand
*broadcaststhem.
*/
publicvoidrun(){
try{
//Createcharacterstreamsforthesocket.
in=newBufferedReader(newInputStreamReader(
socket.getInputStream()));
out=new

PrintWriter(socket.getOutputStream(),true);
//Requestanamefromthisclient.Keep
requestinguntil
//anameissubmittedthatisnotalready
used.Notethat
//checkingfortheexistenceofanameand
addingthename
//mustbedonewhilelockingthesetof
names.
while(true){
out.println("SUBMITNAME");
name=in.readLine();
if(name==null){
return;
}
synchronized(names){
if(!names.contains(name)){
names.add(name);
break;
}
}
}
//Nowthatasuccessfulnamehasbeenchosen,
addthe
//socket'sprintwritertothesetofall
writersso
//thisclientcanreceivebroadcastmessages.
out.println("NAMEACCEPTED");
writers.add(out);
//Acceptmessagesfromthisclientand
broadcastthem.
//Ignoreotherclientsthatcannotbe
broadcastedto.
while(true){
Stringinput=in.readLine();
if(input==null){
return;

}
for(PrintWriterwriter:writers){
writer.println("MESSAGE"+name+":
"+input);
}
}
}catch(IOExceptione){
System.out.println(e);
}finally{
//Thisclientisgoingdown!Removeitsname
anditsprint
//writerfromthesets,andcloseitssocket.
if(name!=null){
names.remove(name);
}
if(out!=null){
writers.remove(out);
}
try{
socket.close();
}catch(IOExceptione){
}
}
}
}
}

The client
ChatClient.java
packageedu.lmu.cs.networking;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;

importjava.net.Socket;
importjavax.swing.JFrame;
importjavax.swing.JOptionPane;
importjavax.swing.JScrollPane;
importjavax.swing.JTextArea;
importjavax.swing.JTextField;
/**
*AsimpleSwingbasedclientforthechatserver.
Graphically
*itisaframewithatextfieldforenteringmessagesanda
*textareatoseethewholedialog.
*
*TheclientfollowstheChatProtocolwhichisasfollows.
*Whentheserversends"SUBMITNAME"theclientreplieswith
the
*desiredscreenname.Theserverwillkeepsending
"SUBMITNAME"
*requestsaslongastheclientsubmitsscreennamesthat
are
*alreadyinuse.Whentheserversendsalinebeginning
*with"NAMEACCEPTED"theclientisnowallowedtostart
*sendingtheserverarbitrarystringstobebroadcasttoall
*chattersconnectedtotheserver.Whentheserversendsa
*linebeginningwith"MESSAGE"thenallcharacters
following
*thisstringshouldbedisplayedinitsmessagearea.
*/
publicclassChatClient{
BufferedReaderin;
PrintWriterout;
JFrameframe=newJFrame("Chatter");
JTextFieldtextField=newJTextField(40);
JTextAreamessageArea=newJTextArea(8,40);
/**
*ConstructstheclientbylayingouttheGUIand
registeringa

*listenerwiththetextfieldsothatpressingReturnin
the
*listenersendsthetextfieldcontentstotheserver.
Note
*howeverthatthetextfieldisinitiallyNOTeditable,
and
*onlybecomeseditableAFTERtheclientreceivesthe
NAMEACCEPTED
*messagefromtheserver.
*/
publicChatClient(){
//LayoutGUI
textField.setEditable(false);
messageArea.setEditable(false);
frame.getContentPane().add(textField,"North");
frame.getContentPane().add(new
JScrollPane(messageArea),"Center");
frame.pack();
//AddListeners
textField.addActionListener(newActionListener(){
/**
*Respondstopressingtheenterkeyinthe
textfieldbysending
*thecontentsofthetextfieldtotheserver.
Thenclear
*thetextareainpreparationforthenext
message.
*/
publicvoidactionPerformed(ActionEvente){
out.println(textField.getText());
textField.setText("");
}
});
}
/**
*Promptforandreturntheaddressoftheserver.
*/

privateStringgetServerAddress(){
returnJOptionPane.showInputDialog(
frame,
"EnterIPAddressoftheServer:",
"WelcometotheChatter",
JOptionPane.QUESTION_MESSAGE);
}
/**
*Promptforandreturnthedesiredscreenname.
*/
privateStringgetName(){
returnJOptionPane.showInputDialog(
frame,
"Chooseascreenname:",
"Screennameselection",
JOptionPane.PLAIN_MESSAGE);
}
/**
*Connectstotheserverthenenterstheprocessingloop.
*/
privatevoidrun()throwsIOException{
//Makeconnectionandinitializestreams
StringserverAddress=getServerAddress();
Socketsocket=newSocket(serverAddress,9001);
in=newBufferedReader(newInputStreamReader(
socket.getInputStream()));
out=newPrintWriter(socket.getOutputStream(),true);
//Processallmessagesfromserver,accordingtothe
protocol.
while(true){
Stringline=in.readLine();
if(line.startsWith("SUBMITNAME")){
out.println(getName());
}elseif(line.startsWith("NAMEACCEPTED")){
textField.setEditable(true);
}elseif(line.startsWith("MESSAGE")){

messageArea.append(line.substring(8)+"\n");
}
}
}
/**
*Runstheclientasanapplicationwithacloseable
frame.
*/
publicstaticvoidmain(String[]args)throwsException{
ChatClientclient=newChatClient();

client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setVisible(true);
client.run();
}
}

Vous aimerez peut-être aussi