这是一个课后练习。主要是熟练掌握IO流,还有TCP程序的一般开发步骤。
TCP程序开发的一般步骤:
Server端:
1. 创建ServerSocket ss在这里要指定监听端口。
2. 获得Socket s 通过ss.accept()方法获得客户端的连接请求。
3. 获得IO流 通过s.getInputStream和s.getOutputStream两个方法获得输入输出流
4. 处理数据,传送数据。
5. 关闭IO流
6. 关闭Socket s
7. 关闭ServerSocket ss
Client端:
1. 创建Socket s 在这里指定网络主机及其相应端口。
2. 获得IO流
3. 处理数据,传送数据
4. 关闭IO流
5. 关闭Socket s
本程序的基本功能是连接到服务器,在提交一个文件路径后,服务器判断是否是文本文件,是并且存在的话就传送文件内容到客户端。
为了功能更加人性化点,在客户端界面加入主机及其端口和文件地址文本框,还有连接,断开连接,下载文件按钮,下载的文件内容显示在文本域中,另外加一条状态栏,用于显示当前客户端状态。在服务器端界面加入监听端口文本框和开始监听按钮,日志信息显示在文本域中。
本程序基本功能实现,但容错性还不是很好。异常没进行处理。
本程序源码如下(开发语言JAVA,开发环境JDK 1.5 Windows 2003):
开发过程中遇到一个难点就是不知道如何判断网络流的结束,文件流中的readLine==null和read==-1都判断不出来,使客户端在等着读但服务器端已经结束。最后通过在服务器端传送完文件后,加传一个标志字符串(quit)用于通知客户端本次数据已经传送完毕。在客户端通过判断接收到的字符串是不是标志字符来结束读循环。但是这样又想到一个问题,那就是服务器端如果不是自己开发的,那怎么样实现两者间的通信呢?现在课程太紧了,暂时没时间处理。
字节流实现:
package server;
import java.awt. * ;
import java.awt.event. * ;
import javax.swing. * ;
import java.net. * ;
import java.io. * ;
import java.util. * ;
class DownServer extends WindowAdapter implements ActionListener
{
JFrame jframe=new JFrame("远程文件查看器服务端");
JPanel jpanel=new JPanel();
JButton startJButton=new JButton("启动");
JLabel label=new JLabel("监听端口");
JTextField portJTextField=new JTextField(6);
JTextArea logJTextArea=new JTextArea();
JScrollPane logJScrollPane=new JScrollPane(logJTextArea);
Date d=new Date();
ServerSocket ss;
Socket s;
InputStream is;
OutputStream os;
BufferedInputStream bis;
BufferedOutputStream bos=null;
BufferedReader br;
PrintWriter pw;
byte[] b=new byte[1024];
int len;
StringBuffer sb;
String filename;
String port="6666";
public DownServer()
{
jpanel.add(label);
jpanel.add(portJTextField);
jpanel.add(startJButton);
startJButton.addActionListener(this);
jframe.getContentPane().add(jpanel,"North");
jframe.getContentPane().add(logJScrollPane);
jframe.addWindowListener(this);
jframe.setSize(400,300);
jframe.setResizable(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
String str=e.getActionCommand();
if(str.equals("启动"))
{
port=portJTextField.getText();
logJTextArea.append(d.toString()+": 在 "+port+" 端口启动服务 ");
Server s=new Server();
s.start();
}
if(str.equals("停止"))
{
}
}
class Server extends Thread
{
public void run()
{
try{ss=new ServerSocket(Integer.parseInt(port));}catch(Exception e){e.printStackTrace();}
while(true)
{
try
{
s=ss.accept();
is=s.getInputStream();
os=s.getOutputStream();
bos=new BufferedOutputStream(os);
br=new BufferedReader(new InputStreamReader(is));
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+" 请求连接成功! ");
}
catch(Exception e){e.printStackTrace();}
sb=new StringBuffer();
while(true)
{
try{filename=br.readLine();}catch(Exception e){e.printStackTrace();}
if(filename.equals("quit"))
{
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"与服务器断开连接 ");
try
{
bos.close();
s.close();
}
catch(Exception e){e.printStackTrace();}
finally
{
break;
}
}
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+" 请求查看文件 "+filename+" ");
File f=new File(filename);
if(f.exists())
{
if(filename.endsWith(".java")||filename.endsWith(".txt")||filename.endsWith(".html")||filename.endsWith(".jsp")||filename.endsWith(".asp")||filename.endsWith(".css")||filename.endsWith(".xml"))
{
try
{
FileInputStream fis=new FileInputStream(f);
BufferedInputStream bis=new BufferedInputStream(fis);
byte[] b=new byte[1024];
int len=0;
StringBuffer sb=new StringBuffer();
while((len=bis.read(b))!=-1)
{
bos.write(b,0,len);
bos.flush();
}
bis.close();
bos.write("quit".getBytes());
bos.flush();
// bos.close();
}catch(Exception ex){}
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"文件传送成功 ");
}
else
{
try
{
bos.write("此文件不是文本文件!".getBytes());
bos.flush();
bos.write("quit".getBytes());
bos.flush();
}catch(Exception e){e.printStackTrace();}
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"非文本文件,没有传送 ");
}
}
else
{
try
{
bos.write("文件不存在".getBytes());
bos.flush();
bos.write("quit".getBytes());
bos.flush();
}catch(Exception e){e.printStackTrace();}
logJTextArea.append(s.getInetAddress()+" 在 "+d.toString()+"文件不存在,没有传送 ");
}
// bos.close();//输出流关闭后Socket也会关闭?//但不关那边又读不完?
}
// bos.close();
// s.close();
// ss.close();
}
}
}
public void windowClosing(WindowEvent e)
{
try
{
bos.close();//如何知道一个流是否有被关闭了????
if(s.isConnected())s.close();//s和ss还没有被创建呀.
if(!ss.isClosed())ss.close();
}
catch(Exception ex){ex.printStackTrace();}
System.exit(0);
}
public static void main(String[] args) throws IOException
{
new DownServer();
}
}
package client;
import java.awt. * ;
import java.awt.event. * ;
import java.io. * ;
import javax.swing. * ;
import java.net. * ;
class DownLoad implements ActionListener
{
JFrame frame=new JFrame("文本文件下载器");
JTextField statu=new JTextField("断开连接");
JTextField tfipaddress=new JTextField(16);
JTextField tfport=new JTextField(5);
JTextField tffilepath=new JTextField(30);
JLabel lbaddress=new JLabel("服务器地址:");
JLabel lbport=new JLabel("端口:");
JLabel lbfilepath=new JLabel("文件地址");
JButton btconnect=new JButton("连接");
JButton btdisconnect=new JButton("断开连接");
JButton btdownload=new JButton("下载");
JTextArea tadownresult=new JTextArea(20,50);
JScrollPane spdownresult=new JScrollPane(tadownresult);
//JStatuBar
JPanel northpanel=new JPanel();
JPanel centerpanel=new JPanel();
JPanel northpanel1=new JPanel();
JPanel northpanel2=new JPanel();
String address="127.0.0.1";
String port="6666";
Socket s;
InputStream is;
OutputStream os;
BufferedInputStream bis;
BufferedOutputStream bos;
BufferedReader br;
PrintWriter pw;
byte[] b=new byte[1024];
int len;
StringBuffer sb=new StringBuffer();
public DownLoad()
{
init();
addListener();
showFrame();
}
public void init()
{
frame.add(northpanel,"North");
frame.add(centerpanel);
frame.add(statu,"South");
statu.enable(false);
btdisconnect.setEnabled(false);
btdownload.setEnabled(false);
northpanel.setLayout(new BorderLayout());
northpanel.add(northpanel1,"North");
northpanel.add(northpanel2);
northpanel1.setLayout(new FlowLayout(FlowLayout.LEFT));
northpanel1.add(lbaddress);
northpanel1.add(tfipaddress);
northpanel1.add(lbport);
northpanel1.add(tfport);
northpanel1.add(btconnect);
northpanel1.add(btdisconnect);
northpanel2.setLayout(new FlowLayout(FlowLayout.LEFT));
northpanel2.add(lbfilepath);
northpanel2.add(tffilepath);
northpanel2.add(btdownload);
centerpanel.setLayout(new BorderLayout());
centerpanel.add(spdownresult);
}
public void showFrame()
{
frame.pack();
// frame.setSize(800,600);
frame.setResizable(true);
frame.setLocation(100,50);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void addListener()
{
btconnect.addActionListener(this);
btdisconnect.addActionListener(this);
btdownload.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
String action=e.getActionCommand();
if(action.equals("连接"))
{
if(!tfipaddress.getText().equals(""))address=tfipaddress.getText();
if(!tfport.getText().equals(""))port=tfport.getText();
try{s=new Socket(address,Integer.parseInt(port));receiveStream();}catch(Exception ex){ex.printStackTrace();}//如何设置一个Socket的连接超时?有ServerSocket设置.
if(s.isConnected())
{
statu.setText("已经连接");
btconnect.setEnabled(false);
btdisconnect.setEnabled(true);
btdownload.setEnabled(true);
}
else
{
statu.setText("连接超时");
}
}
if(action.equals("断开连接"))
{
try
{
pw.println("quit");
pw.flush();
pw.close();
s.close();
}catch(Exception ee){}
statu.setText("断开连接");
btconnect.setEnabled(true);
btdisconnect.setEnabled(false);
btdownload.setEnabled(false);
}
if(action.equals("下载"))
{
tadownresult.setText("");
String filename=tffilepath.getText();
try
{
pw.println(filename);
pw.flush();
while(true)
{
len=bis.read(b);
String str=new String(b,0,len);
if(str.equals("quit"))break;
tadownresult.append(str+" ");
// String s=new String(b,0,len);
// sb.append(s);
}
// String st=sb.toString();
// System.out.println (st);
// tadownresult.setText(st);
}
catch(IOException eo){}
}
}
public void receiveStream()
{
try
{
is=s.getInputStream();
os=s.getOutputStream();
bis=new BufferedInputStream(is);
pw=new PrintWriter(os);
}
catch(IOException ex){}
}
public static void main(String[] args)
{
new DownLoad();
}
}
字符流实现:
package server;
import java.net. * ;
import java.io. * ;
import java.awt. * ;
import java.awt.event. * ;
import javax.swing. * ;
import java.util.Date;
class Server
{
JFrame frame=new JFrame("文件下载服务器端");
JPanel panel=new JPanel();
JTextArea textarea=new JTextArea();
JScrollPane scrollpane=new JScrollPane(textarea);
JTextField port=new JTextField(5);
JLabel label=new JLabel("监听端口:");
JButton button=new JButton("启动");
ServerSocket ss=null;
Date d=new Date();
public Server()
{
init();
}
public void init()
{
frame.add(panel,"North");
frame.add(scrollpane);
panel.add(label);
panel.add(port);
panel.add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(port.getText().equals(""))
{
JOptionPane jop=new JOptionPane();
jop.showMessageDialog(frame,"端口号不能为空");
return;
}
else
{
try
{
ss=new ServerSocket(Integer.parseInt(port.getText()));
textarea.setText(d.toString()+" 在端口:"+port.getText()+" 启动文件下载服务 ");
DownServer ds=new DownServer();
ds.start();
}
catch(Exception io){io.printStackTrace();}
}
}
});
frame.setSize(800,600);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) throws IOException
{
new Server();
}
class DownServer extends Thread
{
InputStream is;
OutputStream os;
BufferedInputStream bis;
BufferedOutputStream bos;
BufferedReader br;
PrintWriter pw;
byte[] b=new byte[1024];
int len;
StringBuffer sb;
String filename;
public void run()
{
String address=null;
while(true)
{
try
{
Socket s=ss.accept();
is=s.getInputStream();
os=s.getOutputStream();
address=s.getInetAddress().toString();
//字符流处理
br=new BufferedReader(new InputStreamReader(is));
pw=new PrintWriter(os);
textarea.append(address+" 在 "+d.toString()+" : 连接 ");
}
catch(Exception ex){ex.printStackTrace();}
sb=new StringBuffer();
while(true)
{
//字符流处理
try
{
filename=br.readLine();
}
catch(Exception ee){ee.printStackTrace();System.out.println ("异常!!!!!!!!");}
if(filename.equals("quit"))
{
textarea.append(address+" 在 "+d.toString()+" : 断开连接 ");
break;
}
File f=new File(filename);
textarea.append(address+" "+d.toString()+" : 访问文件 "+filename+" ");
if(f.exists())
{
if(filename.endsWith(".java")||filename.endsWith(".txt")||filename.endsWith(".html")||filename.endsWith(".jsp")||filename.endsWith(".asp")||filename.endsWith(".css")||filename.endsWith(".xml"))
{
try
{
//字符流处理
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader (fr); //使用ReadLine()一次读一行,怎么知道文件结束?
String str=null;
while((str=br.readLine())!=null)
{
pw.println(str);
pw.flush();
}
br.close();
textarea.append(address+" "+d.toString()+" : 访问文件 "+filename+" 成功 ");
pw.println("quit");
pw.flush();
}catch(Exception ex){}
}
else
{
//字符流处理
pw.println("此文件不是文本文件!");
pw.flush();
textarea.append(address+" "+d.toString()+" 不是文本文件,下载失败 ");
pw.println("quit"); //(1)可以两边同时使用一个信息表示结束.(2)服务器端不做结束警告,客户端通过捕捉异常来结束.
pw.flush();
}
}
else
{
//字符流处理
pw.println("文件不存在");
pw.flush();
textarea.append(address+" "+d.toString()+" 文件不存在,下载失败 ");
pw.println("quit");
pw.flush();
}
// pw.close();//不关闭,客户端读不完,关闭,Socket也关了??????
}
// pw.close();
// s.close();
// ss.close();
}
}
}
}
package client;
import java.awt. * ;
import java.awt.event. * ;
import java.io. * ;
import javax.swing. * ;
import java.net. * ;
class DownLoad extends WindowAdapter implements ActionListener
{
JFrame frame=new JFrame("文本文件下载器");
JTextField statu=new JTextField("断开连接");
JTextField tfipaddress=new JTextField(16);
JTextField tfport=new JTextField(5);
JTextField tffilepath=new JTextField(30);
JLabel lbaddress=new JLabel("服务器地址:");
JLabel lbport=new JLabel("端口:");
JLabel lbfilepath=new JLabel("文件地址");
JButton btconnect=new JButton("连接");
JButton btdisconnect=new JButton("断开连接");
JButton btdownload=new JButton("下载");
JTextArea tadownresult=new JTextArea(20,50);
JScrollPane spdownresult=new JScrollPane(tadownresult);
//JStatuBar
JPanel northpanel=new JPanel();
JPanel centerpanel=new JPanel();
JPanel northpanel1=new JPanel();
JPanel northpanel2=new JPanel();
Socket s;
InputStream is;
OutputStream os;
BufferedInputStream bis;
BufferedOutputStream bos;
BufferedReader br;
PrintWriter pw;
byte[] b=new byte[1024];
int len;
StringBuffer sb=new StringBuffer();
public DownLoad()
{
init();
addListener();
showFrame();
}
public void init()
{
frame.add(northpanel,"North");
frame.add(centerpanel);
frame.add(statu,"South");
statu.enable(false);
btdisconnect.setEnabled(false);
btdownload.setEnabled(false);
northpanel.setLayout(new BorderLayout());
northpanel.add(northpanel1,"North");
northpanel.add(northpanel2);
northpanel1.setLayout(new FlowLayout(FlowLayout.LEFT));
northpanel1.add(lbaddress);
northpanel1.add(tfipaddress);
tfipaddress.setText("127.0.0.1");
northpanel1.add(lbport);
northpanel1.add(tfport);
tfport.setText("6666");
northpanel1.add(btconnect);
northpanel1.add(btdisconnect);
northpanel2.setLayout(new FlowLayout(FlowLayout.LEFT));
northpanel2.add(lbfilepath);
northpanel2.add(tffilepath);
northpanel2.add(btdownload);
centerpanel.setLayout(new BorderLayout());
centerpanel.add(spdownresult);
frame.addWindowListener(this);
}
public void showFrame()
{
frame.pack();
// frame.setSize(800,600);
frame.setResizable(true);
frame.setLocation(100,50);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void addListener()
{
btconnect.addActionListener(this);
btdisconnect.addActionListener(this);
btdownload.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
String action=e.getActionCommand();
if(action.equals("连接"))
{
String address=tfipaddress.getText();
String port=tfport.getText();
if(address.equals("")||port.equals(""))
{
JOptionPane jop=new JOptionPane();
jop.showMessageDialog(frame,"IP地址或端口号为空");
return;
}
try
{
s=new Socket(address,Integer.parseInt(port));
receiveStream();
}catch(Exception ex)
{
statu.setText("连接失败");
return;
}//如何设置一个Socket的连接超时?有ServerSocket设置.
if(s.isConnected())
{
statu.setText("已经连接");
btconnect.setEnabled(false);
btdisconnect.setEnabled(true);
btdownload.setEnabled(true);
}
else
{
statu.setText("连接超时");
}
}
if(action.equals("断开连接"))
{
try
{
pw.println("quit");
pw.flush();
pw.close();
s.close();
}catch(Exception ee){System.out.println ("发生异常");}
statu.setText("断开连接");
btconnect.setEnabled(true);
btdisconnect.setEnabled(false);
btdownload.setEnabled(false);
}
if(action.equals("下载"))
{
String filename=tffilepath.getText();
try
{
//字符流处理
pw.println(filename);
pw.flush();
tadownresult.setText("");
sb=sb.delete(0,sb.length());
String str=null;
while(true)
{
str=br.readLine();
if(str.equals("quit"))break;
sb.append(str+" ");
// tadownresult.append(str+" ");
}
tadownresult.setText(sb.toString());
}
catch(IOException eo){}
}
}
public void receiveStream()
{
try
{
is=s.getInputStream();
os=s.getOutputStream();
//字符流处理
br=new BufferedReader(new InputStreamReader(is));
pw=new PrintWriter(os);
}
catch(IOException ex){}
}
public static void main(String[] args)
{
new DownLoad();
}
public void windowClosing(WindowEvent we)
{
if(s!=null)
{
if(s.isConnected())
{
pw.println("quit");
pw.flush();
pw.close();
try{s.close();}catch(IOException ioe){ioe.printStackTrace();}
}
}
System.exit(0);
}
}