Java开发网 |
注册 |
登录 |
帮助 |
搜索 |
排行榜 |
发帖统计
|
您没有登录 |
» Java开发网 » Java SE 综合讨论区
打印话题 寄给朋友 订阅主题 |
作者 | java 网络编程 |
cckoan
Smoking CJSDN高级会员 发贴: 253 积分: 130 |
于 2002-12-31 10:32
HTTP协议 超文本传输协议(HTTP)是位于TCP/IP 协议的应用层,是最广为人知的协议,也是互连网中最核心的协议之一,同样,HTTP 也是基于 C/S 或 B/S 模型实现的。事实上,我们使用的浏览器如Netscape 或IE 是实现HTTP 协议中的客户端,而一些常用的Web 服务器软件如Apache、IIS 和iPlanet Web Server 等是实现HTTP 协议中的服务器端。Web 页由服务端资源定位,传输到浏览器,经过浏览器的解释后,被客户所看到。 Web 的工作基于客户机/服务器计算模型,由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。 一个完整的HTTP协议会话过程包括四个步骤: ◆ 连接,Web浏览器与Web服务器建立连接,打开一个称为Socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功; ◆ 请求,Web浏览器通过Socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递); ◆ 应答,Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器,从而在Web浏览器上显示出所请求的页面; ◆ 关闭连接,应答结束后Web浏览器与Web服务器必须断开,以保证其它Web浏览器能够与Web服务器建立连接。 Java实现Web服务器功能的程序设计 编程思路 根据上述HTTP协议的会话过程,本实例中实现了GET请求的Web服务器程序的方法,方法如下: 通过创建ServerSocket 类对象,侦听用户指定的端口(为8080),等待并接受客户机请求到端口。创建与Socket相关联的输入流和输出流,然后读取客户机的请求信息。若请求类型是GET,则从请求信息中获取所访问的HTML 文件名;如果HTML 文件存在,则打开HTML 文件,把HTTP 头信息和HTML 文件内容通过Socket 传回给Web浏览器,然后关闭文件,否则发送错误信息给Web 浏览器。最后关闭与相应Web 浏览器连接的Socket。 用Java编写Web服务器httpServer.java文件的源代码如下: //httpServer.java import java.net.*; import java.io.*; import java.util.*; import java.lang.*; public class httpServer{ public static void main(String args[]) { int port; ServerSocket server_socket; //读取服务器端口号 try { port = Integer.parseInt(args[0]); } catch (Exception e) { port = 8080; } try { //监听服务器端口,等待连接请求 server_socket = new ServerSocket(port); System.out.println("httpServer running on port " + server_socket.getLocalPort()); //显示启动信息 while(true) { Socket socket = server_socket.accept(); System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort()); //创建分线程 try { httpRequestHandler request = new httpRequestHandler(socket); Thread thread = new Thread(request); //启动线程 thread.start(); } catch(Exception e) { System.out.println; } } } catch (IOException e) { System.out.println; } } } class httpRequestHandler implements Runnable { final static String CRLF = "\r\n"; Socket socket; InputStream input; OutputStream output; BufferedReader br; // 构造方法 public httpRequestHandler(Socket socket) throws Exception { this.socket = socket; this.input = socket.getInputStream(); this.output = socket.getOutputStream(); this.br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } // 实现Runnable 接口的run()方法 public void run() { try { processRequest(); } catch(Exception e) { System.out.println; } } private void processRequest() throws Exception { while(true) { //读取并显示Web 浏览器提交的请求信息 String headerLine = br.readLine(); System.out.println("The client request is "+headerLine); if(headerLine.equals(CRLF) || headerLine.equals("")) break; StringTokenizer s = new StringTokenizer(headerLine); String temp = s.nextToken(); if(temp.equals("GET")) { String fileName = s.nextToken(); fileName = "." + fileName ; // 打开所请求的文件 FileInputStream fis = null ; boolean fileExists = true ; try { fis = new FileInputStream( fileName ) ; } catch ( FileNotFoundException e ) { fileExists = false ; } // 完成回应消息 String serverLine = "Server: a simple java httpServer"; String statusLine = null; String contentTypeLine = null; String entityBody = null; String contentLengthLine = "error"; if ( fileExists ) { statusLine = "HTTP/1.0 200 OK" + CRLF ; contentTypeLine = "Content-type: " + contentType( fileName ) + CRLF ; contentLengthLine = "Content-Length: " + (new Integer(fis.available())).toString() + CRLF; } else { statusLine = "HTTP/1.0 404 Not Found" + CRLF ; contentTypeLine = "text/html" ; entityBody = "<HTML>" + "<HEAD><TITLE>404 Not Found</TITLE></HEAD>" + "<BODY>404 Not Found" +"<br>usage:http://yourHostName:port/" +"fileName.html</BODY></HTML>" ; } // 发送到服务器信息 output.write(statusLine.getBytes()); output.write(serverLine.getBytes()); output.write(contentTypeLine.getBytes()); output.write(contentLengthLine.getBytes()); output.write(CRLF.getBytes()); // 发送信息内容 if (fileExists) { sendBytes(fis, output) ; fis.close(); } else { output.write(entityBody.getBytes()); } } } //关闭套接字和流 try { output.close(); br.close(); socket.close(); } catch(Exception e) {} } private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception { // 创建一个 1K buffer byte[] buffer = new byte[1024] ; int bytes = 0 ; // 将文件输出到套接字输出流中 while ((bytes = fis.read(buffer)) != -1 ) { os.write(buffer, 0, bytes); } } private static String contentType(String fileName) { if (fileName.endsWith(".htm") || fileName.endsWith(".html")) { return "text/html"; } return "fileName"; } } 编程技巧说明 ◆ 主线程设计 主线程的设计就是在主线程httpServer 类中实现了服务器端口的侦听,服务器接受一个客户端请求之后创建一个线程实例处理请求,代码如下: import java.net.*; import java.io.*; import java.util.*; import java.lang.*; public class httpServer{ public static void main(String args[]) { port; ServerSocket server_socket; //读取服务器端口号 try { port = Integer.parseInt(args[0]); } catch (Exception e) { port = 8080; } try { //监听服务器端口,等待连接请求 server_socket = new ServerSocket(port); System.out.println("httpServer running on port " +server_socket.getLocalPort()); .......... .......... ◆ 连接处理分线程设计 在分线程httpRequestHandler 类中实现了HTTP 协议的处理,这个类实现了Runnable 接口,代码如下: class httpRequestHandler implements Runnable { final static String CRLF = "\r\n"; Socket socket; InputStream input; OutputStream output; BufferedReader br; // 构造方法 public httpRequestHandler(Socket socket) throws Exception { this.socket = socket; //得到输入输出流 this.input = socket.getInputStream(); this.output = socket.getOutputStream(); this.br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } // 实现Runnable 接口的run()方法 public void run() { try { processRequest(); } catch(Exception e) { System.out.println; } } ◆ 构建processRequest()方法来处理信息的接收和发送 作为实现Runnable 接口的主要内容,在run()方法中调用processRequest()方法来处理客户请求内容的接收和服务器返回信息的发送,代码如下: private void processRequest() throws Exception { while(true) { //读取并显示Web 浏览器提交的请求信息 String headerLine = br.readLine(); System.out.println("The client request is "+ headerLine); if(headerLine.equals(CRLF) || headerLine.equals("")) break; //根据请求字符串中的空格拆分客户请求 StringTokenizer s = new StringTokenizer(headerLine); String temp = s.nextToken(); if(temp.equals("GET")) { String fileName = s.nextToken(); fileName = "." + fileName ; ............. ............. 在processRequest()方法中得到客户端请求后,利用一个StringTokenizer 类完成了字符串的拆分,这个类可以实现根据字符串中指定的分隔符(缺省为空格)将字符串拆分成为字串的功能。利用nextToken()方法依次得到这些字串;sendBytes()方法完成信息内容的发送,contentType()方法用于判断文件的类型。 显示Web页面 显示 Web 页面的index.html 文件代码如下: <html> <head> <meta http-equiv="Content-Language" content="zh-cn"> <meta name="GENERATOR" content="Microsoft FrontPage 5.0"> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>Java Web 服务器</title> </head> <body> <p>********* <font color="#FF0000">欢迎你的到来!</font>*********</p> <p>这是一个用 Java 语言实现的 Web 服务器</p> <hr> </body> </html> 运行实例 为了测试上述程序的正确性,将编译后的httpServer.class、httpRequestHandler.class和上面的index.html文件置于网络的某台主机的同一目录中。 首先运行服务器程序 java httpServer 8080,服务器程序运行后显示端口信息“httpServer runing on port 8080”, 然后在浏览器的地址栏中输入http://localhost:8080/index.html,就可以正确显示网页,同时在显示“httpServer runing on port 8080 ”窗口中服务器会出现一些信息。 SMTP 电子邮件传递可以由多种协议来实现。目前,在Internet 网上最流行的三种电子邮件协议是SMTP、POP3 和 IMAP,下面分别简单介绍。 ◆ SMTP 协议 简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)是一个运行在TCP/IP之上的协议,用它发送和接收电子邮件。SMTP 服务器在默认端口25上监听。SMTP客户使用一组简单的、基于文本的命令与SMTP服务器进行通信。在建立了一个连接后,为了接收响应,SMTP客户首先发出一个命令来标识它们的电子邮件地址。如果SMTP服务器接受了发送者发出的文本命令,它就利用一个OK响应和整数代码确认每一个命令。客户发送的另一个命令意味着电子邮件消息体的开始,消息体以一个圆点“.”加上回车符终止。 ◆ POP3 协议 邮局协议(Post Office Protocol Version 3,POP3)提供了一种对邮件消息进行排队的标准机制,这样接收者以后才能检索邮件。POP3服务器也运行在TCP/IP之上,并且在默认端口110上监听。在客户和服务器之间进行了初始的会话之后,基于文本的命令序列可以被交换。POP3客户利用用户名和口令向POP3服务器认证。POP3中的认证是在一种未加密的会话基础之上进行的。POP3客户发出一系列命令发送给POP3服务器,如:请求客户邮箱队列的状态、请求列出的邮箱队列的内容和请求检索实际的消息。POP3代表一种存储转发类型的消息传递服务。现在,大部分邮件服务器都采用SMTP发送邮件,同时使用POP3接收电子邮件消息。 ◆ IMAP 协议 Internet 消息访问协议(Internet Message Access Protocol,IMAP)是一种电子邮件消息排队服务,它对POP3的存储转发限制提供了重要的改进。IMAP也使用基于文本命令的语法在TCP/IP上运行,IMAP服务器一般在默认端口143监听。IMAP服务器允许IMAP客户下载一个电子邮件的头信息,并且不要求将整个消息从服务器下载至客户,这一点与POP3是相同的。IMAP服务器提供了一种排队机制以接收消息,同时必须与SMTP相结合在一起才能发送消息。 下面以SMTP发送电子邮件为例讲解怎样用Java 实现SMTP 服务器应用功能,从而完成邮件的发送的。 SMTP 命令 SMTP协议是目前网上流行的发送E-Mail的协议,SMTP协议共有14条命令。不过,发一封E-Mail只需用如下5条命令就足够了,分别为: ◆ HELO <SP> <domain> <CRLF> ,与SMTP服务器握手,传送本机域名; ◆ MAIL <SP> FROM:<reverse-path> <CRLF>,传送发信者的信箱名称; ◆ RCPT <SP> TO:<forward-path> <CRLF>,传送接收者的信箱名称; ◆ DATA <CRLF>,发送信件数据(包括信头和信体); ◆ QUIT <CRLF>,退出与SMTP服务器的连接。 编程思路 首先我们设计一个邮件发送程序的交互界面,界面中包括用户输入邮件的收件人、发信人和主题组件的单行文本框,书写邮件内容的多行文本框等。然后为了能够实现E-mail的发送和设置,我们设计一个SmtpMail类,它封装了与邮件服务器之间的Socket 通信操作,以及SMTP 命令的发送和响应信息的接收。 编程技巧说明 1.设置窗体和组件 我们设计了一个MailSendFrame()类继承Frame 对象,作为容纳组件的主窗体。Main()函数实现将窗体启动时置于屏幕的正中央,窗口定义代码如下: public static void main(String[] args) { mailSendFrame mailSendFrame = new mailSendFrame(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = mailSendFrame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } mailSendFrame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); mailSendFrame.setVisible(true); mailSendFrame.show(); } 在Main()函数中,首先利用代表系统信息的Toolkit对象得到当前系统中设置的屏幕分辨率,并且用分辨率和窗体的大小作比较,然后,调用MailSendFrame的SetLocation()方法设置窗体的左上角坐标,使窗体的中心和屏幕的中心正好重合,从而将窗体居中。 //组件实例变量的定义 Panel panelMain = new Panel(); Panel panelUp = new Panel(); Panel panel3 = new Panel(); Panel panel4 = new Panel(); Panel panel6 = new Panel(); Panel panel7 = new Panel(); TextField txtServer = new TextField(); TextField txtTo = new TextField(); TextField txtFrom = new TextField(); TextField txtSubject = new TextField(); Panel panel8 = new Panel(); Label lblFile = new Label(); Button cmdBrowse = new Button(); Panel panelDown = new Panel(); TextArea txtMail = new TextArea(); Panel panel10 = new Panel(); Button cmdSend = new Button(); Button cmdExit = new Button(); ....... ....... panelMain.add(panelUp, null); panelUp.add(panel3, null); panel3.add(new Label("发信服务器:"), null); panel3.add(txtServer, null); panelUp.add(panel4, null); panel4.add(new Label("收件人:"), null); panel4.add(txtTo, null); panelUp.add(panel6, null); panelUp.add(panel7, null); panel7.add(new Label("主题:"), null); panel7.add(txtSubject, null); panel6.add(new Label("发件人:"), null); panel6.add(txtFrom, null); panelUp.add(panel8, null); panel8.add(new Label("附件: "), null); panel8.add(lblFile, null); panel8.add(cmdBrowse, null); panelMain.add(panelDown, null); panelDown.add(txtMail, BorderLayout.CENTER); panelDown.add(panel10, BorderLayout.SOUTH); panel10.add(cmdSend, null); panel10.add(cmdExit, null); panelDown.add(new Label(" "), BorderLayout.EAST); panelDown.add(new Label(" "), BorderLayout.WEST); ........ ........ 窗体组件的定义都是在Init()方法中完成,设置好收件人、发信人和主题组件的单行文本框,书写邮件内容的多行文本框,以及附件中的浏览按钮、发送和退出按钮。 2.窗体中的事件处理 事件处理也是在Init()方法中完成。选取附件文件的“浏览”按钮的事件处理,在单击该按钮时,打开一个OpenFileDialog 文件对话框,读取用户所选取的文件名。打开文件对话框的“浏览”按钮的代码如下: private FileDialog openFileDialog= new FileDialog(this,"打开文件",FileDialog.LOAD); public mailSendFrame() { try { Init(); } catch(Exception e) { e.printStackTrace(); } } ...... ...... 单击“发送”按钮的事件处理,实现用户填写邮件信息的收集和邮件的发送操作。“发送”按钮的代码如下: cmdSend.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { cmdSend_actionPerformed; } } 实现cmdSend_actionPerformed()方法如下: void cmdSend_actionPerformed(ActionEvent e) { mailSender.setFrom(txtFrom.getText().trim()); mailSender.setTo(txtTo.getText().trim()); mailSender.addHeader("Subject",txtSubject.getText().trim()) ; mailSender.addData(txtMail.getText()) ; if(!lblFile.getText().trim().equals("") ) mailSender.addAttachment(lblFile.getText().trim()); mailSender.open(txtServer.getText().trim(),25); mailSender.transmit(); mailSender.close(); } 单击“退出”按钮的事件处理,实现程序的退出和窗体的关闭。“退出”按钮和侦听器的程序代码如下: cmdExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { cmdExit_actionPerformed; } } this.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(WindowEvent e) { this_windowClosing; } } 上面程序分别为退出和窗体注册事件的侦听器或适配器,它们处理各自的交互动作。实现cmdExit_actionPerformed()和this_windowClosing()方法如下: void cmdExit_actionPerformed(ActionEvent e) { System.exit(0); } void this_windowClosing(WindowEvent e) { System.exit(0); } 3.SmtpMail 类的实现 采用Open()方法,建立与邮件服务器之间的TCP/IP 连接,创建套接字,并且得到发送命令所用的输出流Send 和接收服务器相应所用的输入流Rev。Open()方法的代码如下: public int open(String serverName, int port){ try{ mailSocket = new Socket(serverName, port); send = new PrintWriter(mailSocket.getOutputStream(), true); recv = new BufferedReader(new InputStreamReader(mailSocket.getInputStream())); String s1 = recv.readLine(); char c = s1.charAt(0); if((c == '4') | (c == '5')) return 0; } catch(Exception e){ return 0; } return 1; } 在SmtpMail 类中,通过Transmit()方法完成发送任务。Transmit()方法的代码如下: public int transmit(){ boolean flag = true; //发送HELO 命令 if(domain.length() != 0){ int i = sendString("HELO " + domain); if(i != 1) return 0; } //发送MAIL FROM 命令(发件人) if(from.length() != 0){ int j = sendString("MAIL FROM:" + from); if(j != 1) return 0; } //发送RCPT TO 命令(收件人) if(to.length() != 0){ int k = sendString("RCPT TO:" + to); if(k != 1) return 0; } //发送邮件正文(DATA 命令) if(sendString("DATA") != 1) return 0; //发送邮件头信息 for(int l = 0; l < x_set.size(); l += 2){ String s = (String)x_set.elementAt(l); send.println(s + ": " + x_set.elementAt(l + 1)); } //发送时间及相关内容格式说明 if(x_set.indexOf("Date") < 0) send.println("Date: " + (new Date()).toString()); ........ ........ 使用SendString()方法来发送字符串命令,并且接收邮件服务器的响应信息,判断命令是否被接收。返回1表示命令被拒绝执行,返回0表示命令被接受。SendString()方法的代码如下: private int sendString(String s){ String s1 = ""; try{ send.println; s1 = recv.readLine(); } catch(Exception e){ System.out.print(s1); return 0; } if(s1.length() == 0) return 0; char c = s1.charAt(0); return !((c == '4') | (c == '5')) ? 1 : 0; } 使用Close()方法来关闭与服务器之间的套接字连接。该方法发送“QUIT”命令,收到响应消息后,才真正关闭连接。Close()方法的代码如下: public int close(){ int i = 0; try{ i += sendString("QUIT"); mailSocket.close(); } catch(Exception e){ return 0; } return i == 0 ? 1 : 0; } mailSendFrame.java源程序代码如下: import java.awt.*; import java.awt.event.*; public class mailSendFrame extends Frame { smtpMail mailSender=new smtpMail(); Panel panelMain = new Panel(); Panel panelUp = new Panel(); Panel panel3 = new Panel(); Panel panel4 = new Panel(); Panel panel6 = new Panel(); Panel panel7 = new Panel(); TextField txtServer = new TextField(); TextField txtTo = new TextField(); TextField txtFrom = new TextField(); TextField txtSubject = new TextField(); Panel panel8 = new Panel(); Label lblFile = new Label(); Button cmdBrowse = new Button(); Panel panelDown = new Panel(); TextArea txtMail = new TextArea(); Panel panel10 = new Panel(); Button cmdSend = new Button(); Button cmdExit = new Button(); private FileDialog openFileDialog = new FileDialog(this,"打开文件",FileDialog.LOAD); public mailSendFrame() { try { Init(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { mailSendFrame mailSendFrame = new mailSendFrame(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = mailSendFrame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } mailSendFrame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); mailSendFrame.setVisible(true); mailSendFrame.show(); } private void Init() throws Exception { this.setLayout(new BorderLayout()); panelMain.setLayout(new GridLayout(2,1)); panelUp.setLayout(new GridLayout(6,1)); panel3.setLayout(new FlowLayout()); this.setVisible(true); ....... ....... //smtpMail.java 的源代码 import java.io.*; import java.net.Socket; import java.util.*; public class smtpMail{ private boolean sendConf=false; public static final int OK = 1; public static final int ERROR = 0; private static final String TEXT = "1"; private static final String TFILE = "2"; private static final String BFILE = "3"; private static final String CPR = "Java 1.0"; private static final String MAILER = "X-Mailer"; private static final int BUFFER_SIZE = 48; private String DELIMETER; private String SEPARATOR; private static final int HOW_LONG = 6; private static final char SMTP_ERROR_CODE1 = 52; private static final char SMTP_ERROR_CODE2 = 53; private static final int fillchar = 61; private static final String cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; private Socket mailSocket; private BufferedReader recv; private PrintWriter send; private String from; private String to; private String domain; private Vector x_set; private Vector body; private Vector attach; public smtpMail(){ DELIMETER = ""; SEPARATOR = ""; mailSocket = null; recv = null; send = null; from = ""; to = ""; domain = ""; x_set = new Vector(); body = new Vector(); attach = new Vector(); DELIMETER = getId(); SEPARATOR = System.getProperty("file.separator"); } ......... ......... FTP FTP(File Transfer Protocol 文件传输协议)是Internet 上用来传送文件的协议。在Internet上通过FTP 服务器可以进行文件的上传(Upload)或下载(Download)。FTP是实时联机服务,在使用它之前必须是具有该服务的一个用户(用户名和口令),工作时客户端必须先登录到作为服务器一方的计算机上,用户登录后可以进行文件搜索和文件传送等有关操作,如改变当前工作目录、列文件目录、设置传输参数及传送文件等。使用FTP可以传送所有类型的文件,如文本文件、二进制可执行文件、图象文件、声音文件和数据压缩文件等。 FTP 命令 FTP 的主要操作都是基于各种命令基础之上的。常用的命令有: ◆ 设置传输模式,它包括ASCⅡ(文本) 和BINARY 二进制模式; ◆ 目录操作,改变或显示远程计算机的当前目录(cd、dir/ls 命令); ◆ 连接操作,open命令用于建立同远程计算机的连接;close命令用于关闭连接; ◆ 发送操作,put命令用于传送文件到远程计算机;mput 命令用于传送多个文件到远程计算机; ◆ 获取操作,get命令用于接收一个文件;mget命令用于接收多个文件。 编程思路 根据FTP 的工作原理,在主函数中建立一个服务器套接字端口,等待客户端请求,一旦客户端请求被接受,服务器程序就建立一个服务器分线程,处理客户端的命令。如果客户端需要和服务器端进行文件的传输,则建立一个新的套接字连接来完成文件的操作。 编程技巧说明 1.主函数设计 在主函数中,完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir 来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的,缺省为C盘的根目录。 具体的代码如下: public class ftpServer extends Thread{ private Socket socketClient; private int counter; private static String initDir; public static void main(String[] args){ if(args.length != 0) { initDir = args[0]; }else{ initDir = "c:";} int i = 1; try{ System.out.println("ftp server started!"); //监听21号端口 ServerSocket s = new ServerSocket(21); for(;{ //接受客户端请求 Socket incoming = s.accept(); //创建服务线程 new ftpServer(incoming,i).start(); i++; } }catch(Exception e){} } 2. 线程类的设计 线程类的主要设计都是在run()方法中实现。用run()方法得到客户端的套接字信息,根据套接字得到输入流和输出流,向客户端发送欢迎信息。 3. FTP 命令的处理 (1) 访问控制命令 ◆ user name(user) 和 password (pass) 命令处理代码如下: if(str.startsWith("USER")){ user = str.substring(4); user = user.trim(); out.println("331 Password");} if(str.startsWith("PASS")) out.println("230 User "+user+" logged in."); User 命令和 Password 命令分别用来提交客户端用户输入的用户名和口令。 ◆ CWD (CHANGE WORKING DIRECTORY) 命令处理代码如下: if(str.startsWith("CWD")){ String str1 = str.substring(3); dir = dir+"/"+str1.trim(); out.println("250 CWD command succesful"); } 该命令改变工作目录到用户指定的目录。 ◆ CDUP (CHANGE TO PARENT DIRECTORY) 命令处理代码如下: if(str.startsWith("CDUP")){ int n = dir.lastIndexOf("/"); dir = dir.substring(0,n); out.println("250 CWD command succesful"); } 该命令改变当前目录为上一层目录。 ◆ QUIT命令处理代码如下: if(str.startsWith("QUIT")) { out.println("GOOD BYE"); done = true; } 该命令退出及关闭与服务器的连接,输出GOOD BYE。 (2) 传输参数命令 ◆ Port命令处理代码如下: if(str.startsWith("PORT")) { out.println("200 PORT command successful"); int i = str.length() - 1; int j = str.lastIndexOf(","); int k = str.lastIndexOf(",",j-1); String str1,str2; str1=""; str2=""; for(int l=k+1;l<j;l++){ str1 = str2 + str.charAt(l); } for(int l=j+1;l<=i;l++){ str2 = str2 + str.charAt(l); } tempPort = Integer.parseInt(str1) * 16 *16 +Integer.parseInt(str2); } 使用该命令时,客户端必须发送客户端用于接收数据的32位IP 地址和16位 的TCP 端口号。这些信息以8位为一组,使用十进制传输,中间用逗号隔开。 ◆ TYPE命令处理代码如下: if(str.startsWith("TYPE")){ out.println("200 type set"); } TYPE 命令用来完成类型设置。 (3) FTP 服务命令 ◆ RETR (RETEIEVE) 和 STORE (STORE)命令处理的代码 if(str.startsWith("RETR")){ out.println("150 Binary data connection"); str = str.substring(4); str = str.trim(); RandomAccessFile outFile = new RandomAccessFile(dir+"/"+str,"r"); Socket tempSocket = new Socket(host,tempPort); OutputStream outSocket = tempSocket.getOutputStream(); byte byteBuffer[]= new byte[1024]; int amount; try{ while((amount = outFile.read(byteBuffer)) != -1){ outSocket.write(byteBuffer, 0, amount); } outSocket.close(); out.println("226 transfer complete"); outFile.close(); tempSocket.close(); } catch(IOException e){} } if(str.startsWith("STOR")){ out.println("150 Binary data connection"); str = str.substring(4); str = str.trim(); RandomAccessFile inFile = new RandomAccessFile(dir+"/"+str,"rw"); Socket tempSocket = new Socket(host,tempPort); InputStream inSocket = tempSocket.getInputStream(); byte byteBuffer[] = new byte[1024]; int amount; try{ while((amount =inSocket.read(byteBuffer) )!= -1){ inFile.write(byteBuffer, 0, amount); } inSocket.close(); out.println("226 transfer complete"); inFile.close(); tempSocket.close(); } catch(IOException e){} } 文件传输命令包括从服务器中获得文件RETR和向服务器中发送文件STOR,这两个命令的处理非常类似。处理RETR命令时,首先得到用户要获得的文件的名称,根据名称创建一个文件输入流,然后和客户端建立临时套接字连接,并得到一个输出流。随后,将文件输入流中的数据读出并借助于套接字输出流发送到客户端,传输完毕以后,关闭流和临时套接字。 STOR 命令的处理也是同样的过程,只是方向正好相反。 ◆ DELE (DELETE)命令处理代码如下: if(str.startsWith("DELE")){ str = str.substring(4); str = str.trim(); File file = new File(dir,str); boolean del = file.delete(); out.println("250 delete command successful"); } DELE 命令用于删除服务器上的指定文件。 ◆ LIST命令处理代码如下: if(str.startsWith("LIST")) { try{ out.println("150 ASCII data"); Socket tempSocket = new Socket(host,tempPort); PrintWriter out2= new PrintWriter(tempSocket.getOutputStream(),true); File file = new File(dir); String[] dirStructure = new String[10]; dirStructure= file.list(); String strType=""; for(int i=0;i<dirStructure.length;i++){ if( dirStructure[i].indexOf(".") == -1) { strType = "d ";} else {strType = "- ";} out2.println(strType+dirStructure[i]); } tempSocket.close(); out.println("226 transfer complete"); } catch(IOException e){} LIST 命令用于向客户端返回服务器中工作目录下的目录结构,包括文件和目录的列表。处理这个命令时,先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的端口号缺省为1,然后为当前工作目录创建File 对象,利用该对象的list()方法得到一个包含该目录下所有文件和子目录名称的字符串数组,然后根据名称中是否含有文件名中特有的“.”来区别目录和文件。最后,将得到的名称数组通过临时套接字发送到客户端。 用Java 实现Web 服务器功能主要采用的协议是HTTP 协议,即超文本传输协议,根据HTTP 的工作原理(会话过程)分为四个步骤:连接(Connection)、请求(Request)、应答(Response)和关闭(Close),它们分别为: 1. 对于客户机与服务器建立连接是通过Socket来实现的。采用URL提供信息,URL http://<IP 地址>/[端口号]/[路径][?<查询信息>] 2. 客户向服务器提出的请求信息是以请求头的形式发送给服务器。请求头包括HTTP 方法和头字段。 HTTP 方法常用的有GET、HEAD 和POST 等;头字段包括有:DATE、PARGMA、ACCEPT、AOTHORIZATION、FORM 、MESSAGE_ID、BEFERRER、 MIME-VERTION 和 USER-AGENT 等。 3. 服务器对请求做出应答消息包含头字段形式的报文信息。报文第一行是状态行。状态行的格式为“<HTTP 版本号><状态代码><解释短语>”。状态码是个三位数字码,分为四类: ◆ 以 2 开头,表示请求被成功处理; ◆ 以 3 开头,表示请求被重定向; ◆ 以 4 开头,表示客户的请求有错; ◆ 以 5 开头,表示服务器不能满足请求。 解释短语是对状态码的解释。 4. 最后是关闭客户与服务器之间的连接。 用Java 实现SMTP 服务器功能可以采用Java Applet、Java Servlet 和 Java Application 来实现。本文的实例选用的是Java Application 来实现SMTP 发送电子邮件功能。在实际应用中使用Java 语言实现电子邮件的接收和发送功能,即MAIL邮件服务器,一般采用基于JavaMail的邮件系统来实现的。通过配置JavaMail,在此基础上进行适当的编程来实现SMTP、POP3 和IMAP等协议,完成邮件服务器的接收和发送邮件任务。 用Java 实现FTP 服务器主要是在 RFC协议基础上来完成FTP 文件传输功能。使用Java 的服务器Socket来实现客户机和服务器的连接,由客户机发出请求,用户输入需要登录的FTP 服务器地址,同时输入用户名和密码。得到服务器的确认后,用户可以在服务器端进行文件操作,实现文件的上传和下载等功能。 关于女孩子从事软件开发的问题 |
话题树型展开 |
人气 | 标题 | 作者 | 字数 | 发贴时间 |
8854 | java 网络编程 | cckoan | 26850 | 2002-12-31 10:32 |
5854 | Re:java 网络编程 | azwind | 19 | 2003-01-10 23:38 |
6044 | Re:java 网络编程 | justinnc | 3 | 2003-01-14 11:33 |
已读帖子 新的帖子 被删除的帖子 |
Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1 客服电话 18559299278 客服信箱 714923@qq.com 客服QQ 714923 |