当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:16:00  来源:本站整理

一个简单的服务器和客户机程序[Java编程]

赞助商链接



  本文“一个简单的服务器和客户机程序[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
这个例子将以最简单的方法应用套接字对服务器和客户机举行操作.服务器的全部工作就是等候成立一个衔接,然后用那个衔接产生的Socket成立一个InputStream以及一个OutputStream.在这之后,它从InputStream读入的全部东西城市反馈给OutputStream,直到接纳到行中止(END)为止,最后关闭衔接.
客户机衔接与服务器的衔接,然后成立一个OutputStream.文本行通过OutputStream发送.客户机也会成立一个InputStream,用它收听服务器说些什么(本例只不过是反馈回来的一样的字句).
服务器与客户机(程序)都利用一样的端口号,并且客户机操纵本地主机地址衔接位于同一台机械中的服务器(程序),所以没必要在一个物理性的网络里完成测试(在某些配置环境中,大概需求同真正的网络成立衔接,不然程序不能工作——固然实际并不通过那个网络通信).
下面是服务器程序:

//: JabberServer.java
// Very simple server that just
// echoes whatever the client sends.
import java.io.*;
import java.net.*;

public class JabberServer {  
  // Choose a port outside of the range 1-1024:
  public static final int PORT = 8080;
  public static void main(String[] args) 
      throws IOException {
    ServerSocket s = new ServerSocket(PORT);
    System.out.println("Started: " + s);
    try {
      // Blocks until a connection occurs:
      Socket socket = s.accept();
      try {
        System.out.println(
          "Connection accepted: "+ socket);
        BufferedReader in = 
          new BufferedReader(
            new InputStreamReader(
              socket.getInputStream()));
        // Output is automatically flushed
        // by PrintWriter:
        PrintWriter out = 
          new PrintWriter(
            new BufferedWriter(
              new OutputStreamWriter(
                socket.getOutputStream())),true);
        while (true) {  
          String str = in.readLine();
          if (str.equals("END")) break;
          System.out.println("Echoing: " + str);
          out.println(str);
        }
      // Always close the two sockets...
      } finally {
        System.out.println("closing...");
        socket.close();
      }
    } finally {
      s.close();
    }
  } 
} ///:~

可以看到,ServerSocket需求的只是一个端口编号,不需求IP地址(因为它就在这台机械上运行).调用accept()时,办法会暂时陷入停顿状况(堵塞),直到某个客户尝试同它成立衔接.换言之,固然它在那边等候衔接,但其他进程仍能正常运行(参考第14章).建好一个衔接今后,accept()就会返回一个Socket对象,它是那个衔接的代表.
排除套接字的责任在这里得到了很艺术的处理.假定ServerSocket构建器失利,则程序简单地退出(注意必须保证ServerSocket的构建器在失利之后不会留下任何翻开的网络套接字).针对这种情形,main()会“掷”出一个IOException违例,所以没必要利用一个try块.若ServerSocket构建器成功履行,则其他全部办法调用都必须到一个try-finally代码块里追求保护,以确保无论块以什么方法留下,ServerSocket都能精确地关闭.
一样的原理也实用于由accept()返回的Socket.若accept()失利,那么我们必须保证Socket不再存在大概含有任何资源,以便没必要排除它们.但假如履行成功,则后续的语句必须进入一个try-finally块内,以保障在它们失利的情形下,Socket仍能得到精确的排除.由于套接字利用了重要的非内存资源,所以在这里必须分外谨严,必须自己着手将它们排除(Java中没有供应“破坏器”来帮忙我们做这件事情).
无论ServerSocket还是由accept()产生的Socket都打印到System.out里.这意味着它们的toString办法会得到自动调用.这样便产生了:

ServerSocket[addr=0.0.0.0,PORT=0,localport=8080]
Socket[addr=127.0.0.1,PORT=1077,localport=8080]

大家不久就会看到它们若何与客户程序做的事情配合.
程序的下一部份看来仿佛仅仅是翻开文件,以便读取和写入,只是InputStream和OutputStream是从Socket对象成立的.操纵两个“转换器”类InputStreamReader和OutputStreamWriter,InputStream和OutputStream对象已经辨别转换成为Java 1.1的Reader和Writer对象.也可以直接利用Java1.0的InputStream和OutputStream类,但对输出来说,利用Writer方法具有明显的上风.这一上风是通过PrintWriter表现出来的,它有一个过载的构建器,能获得第二个参数——一个布尔值标志,指向能否在每一次println()完毕的时刻自动革新输出(但不实用于print()语句).每次写入了输出内容后(写进out),它的缓冲区必须革新,使信息能正式通过网络传送出去.对目前这个例子来说,革新显得尤为重要,因为客户和服务器在采纳下一步操作之前都要等候一行文本内容的到达.若革新没有发生,那么信息不会进入网络,除非缓冲区满(溢出),这会为本例带来很多问题.
编写网络利用程序时,需求分外注意自动革新机制的利用.每次革新缓冲区时,必须成立和发出一个数据包(数据封).就目前的情形来说,这恰是我们所但愿的,因为假定包内包含了还没有发出的文本行,服务器和客户机之间的彼此“握手”就会终止.换句话说,一行的末尾就是一条消息的末尾.但在其他很多情形下,消息并非用行脱离的,所以不如不用自动革新机制,而用内建的缓冲区判决机制来决意什么时刻发送一个数据包.这样一来,我们可以发出较大的数据包,并且处理进程也能加快.
注意和我们翻开的几近全部数据流一样,它们都要举行缓冲处理.本章末尾有一个操练,清楚展示了假定我们不对数据流举行缓冲,那么会得到什么样的后果(速度会变慢).
无限while循环从BufferedReader in内读取文本行,并将信息写入System.out,然后写入PrintWriter.out.注意这可以是任何数据流,它们只是在表面上同网络衔接.
客户程序发出包含了"END"的行后,程序会中止循环,并关闭Socket.
下面是客户程序的源码:

//: JabberClient.java
// Very simple client that just sends
// lines to the server and reads lines
// that the server sends.
import java.net.*;
import java.io.*;

public class JabberClient {
  public static void main(String[] args) 
      throws IOException {
    // Passing null to getByName() produces the
    // special "Local Loopback" IP address, for
    // testing on one machine w/o a network:
    InetAddress addr = 
      InetAddress.getByName(null);
    // Alternatively, you can use 
    // the address or name:
    // InetAddress addr = 
    //    InetAddress.getByName("127.0.0.1");
    // InetAddress addr = 
    //    InetAddress.getByName("localhost");
    System.out.println("addr = " + addr);
    Socket socket = 
      new Socket(addr, JabberServer.PORT);
    // Guard everything in a try-finally to make
    // sure that the socket is closed:
    try {
      System.out.println("socket = " + socket);
      BufferedReader in =
        new BufferedReader(
          new InputStreamReader(
            socket.getInputStream()));
      // Output is automatically flushed
      // by PrintWriter:
      PrintWriter out =
        new PrintWriter(
          new BufferedWriter(
            new OutputStreamWriter(
              socket.getOutputStream())),true);
      for(int i = 0; i < 10; i ++) {
        out.println("howdy " + i);
        String str = in.readLine();
        System.out.println(str);
      }
      out.println("END");
    } finally {
      System.out.println("closing...");
      socket.close();
    }
  }
} ///:~

在main()中,大家可看到得到本地主机IP地址的InetAddress的三种途径:利用null,利用localhost,大概直接利用保存地址127.0.0.1.当然,假如想通过网络同一台远程主机衔接,也可以换用那台机械的IP地址.打印出InetAddress addr后(通过对toString()办法的自动调用),后果以下:
localhost/127.0.0.1
通过向getByName()传送一个null,它会默许探求localhost,并生成特别的保存地址127.0.0.1.注意在名为socket的套接字成立时,同时利用了InetAddress以及端口号.打印这样的某个Socket对象时,为了真正理解它的含义,请记着一次举世无双的因特网衔接是用下述四种数据标识的:clientHost(客户主机)、clientPortNumber(客户端口号)、serverHost(服务主机)以及serverPortNumber(服务端口号).服务程序启动后,会在本地主机(127.0.0.1)上成立为它分配的端口(8080).一旦客户程序发出恳求,机械上下一个可用的端口就会分配给它(这种情形下是1077),这一行动也在与服务程序相同的机械(127.0.0.1)上举行.目前,为了使数据能在客户及服务程序之间往复传送,每一端都需求知道把数据发到那边.所以在同一个“已知”服务程序衔接的时刻,客户会发出一个“返回地址”,使服务器程序知道将自己的数据发到哪儿.我们在服务器端的示范输出中可以领会到这一情形:
Socket[addr=127.0.0.1,port=1077,localport=8080]
这意味着服务器方才已承受了来自127.0.0.1这台机械的端口1077的衔接,同时监听自己的本地端口(8080).而在客户端:
Socket[addr=localhost/127.0.0.1,PORT=8080,localport=1077]
这意味着客户已用自己的本地端口1077与127.0.0.1机械上的端口8080成立了 衔接.
大家会注意到每次重新启动客户程序的时刻,本地端口的编号城市增添.这个编号从1025(恰好在系统保存的1-1024之外)开始,并会一向增添下去,除非我们重启机械.若重新启动机器,端口号仍旧会从1025开始增值(在Unix机械中,一旦超越保存的套按字范围,数字就会再次从最小的可用数字开始).
成立好Socket对象后,将其转换成BufferedReader和PrintWriter的历程便与在服务器中相同(一样地,两种情形下都要从一个Socket开始).在这里,客户通过发出字串"howdy",并在背面跟随一个数字,从而初始化通信.注意缓冲区必须再次革新(这是自动发生的,通过传送给PrintWriter构建器的第二个参数).若缓冲区没有革新,那么整个会话(通信)城市被挂起,因为用于初始化的“howdy”永久不会发送出去(缓冲区不够满,不足以造成发送行动的自动举行).从服务器返回的每一行城市写入System.out,以考证一切都在正常运转.为中止会话,需求发出一个"END".若客户程序简单地挂起,那么服务器会“掷”出一个违例.
大家在这里可以看到我们采取了一样的办法来确保由Socket代表的网络资源得到精确的排除,这是用一个try-finally块实现的.
套接字成立了一个“专用”衔接,它会一向持续到明确断开衔接为止(专用衔接也大概间接性地断开,前提是某一端大概中间的某条链路呈现弊端而崩溃).这意味着参与衔接的双方都被锁定在通信中,并且无论能否有数据传送,衔接城市持续处于开放状况.从表面看,这仿佛是一种公道的连网方法.但是,它也为网络带来了额外的开销.本章背面会介绍举行连网的另一种方法.采取那种方法,衔接的成立只是暂时的.
  以上是“一个简单的服务器和客户机程序[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • Access 2000教程:1.5 一个简单的数据库
  • 一个简单的服务器和客户机程序
  • <b>操纵Java实现一个简单的递归算法的实例</b>
  • 一个简单的Timer Service
  • 用JBuilder7开辟一个简单的J2EE操纵
  • <b>一个简单的记事本代码(二)</b>
  • 一个简单的记事本代码(三)
  • <b>一个简单的记事本代码(一)</b>
  • [JAVA100例]050、一个简单的Web服务器
  • 一个简单的JAVA日历程序
  • 一个简单的CheckBox Tree实现
  • 用java实现一个简单的序列化的例子
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .