知识大全 Java套接字实现网络编程之基础篇

Posted

篇首语:上下观古今,起伏千万途。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java套接字实现网络编程之基础篇相关的知识,希望对你有一定的参考价值。

Java套接字实现网络编程之基础篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

用Java开发网络软件非常方便和强大 Java的这种力量来源于他独有的一套强大的用于网络的 API 这些API是一系列的类和接口 均位于包和中 在这篇文章中我们将介绍套接字(Socket)慨念 同时以实例说明如何使用Neork API操纵套接字 在完成本文后 你将具备编写网络低端通讯软件的能力    什么是套接字(Socket)?  Neork API是典型的用于基于TCP/IP网络Java程序与其他程序通讯 Neork API依靠Socket进行通讯 Socket可以看成在两个程序进行通讯连接中的一个端点 一个程序将一段信息写入Socket中 该Socket将这段信息发送给另外一个Socket中 使这段信息能传送到其他程序中 如图   我们来分析一下图 Host A上的程序A将一段信息写入Socket中 Socket的内容被Host A的网络管理软件访问 并将这段信息通过Host A的网络接口卡发送到Host B Host B的网络接口卡接收到这段信息后 传送给Host B的网络管理软件 网络管理软件将这段信息保存在Host B的Socket中 然后程序B才能在Socket中阅读这段信息   假设在图 的网络中添加第三个主机Host C 那么Host A怎么知道信息被正确传送到Host B而不是被传送到Host C中了呢?基于TCP/IP网络中的每一个主机均被赋予了一个唯一的IP地址 IP地址是一个 位的无符号整数 由于没有转变成二进制 因此通常以小数点分隔 如 正如所见IP地址均由四个部分组成 每个部分的范围都是 以表示 位地址   值得注意的是IP地址都是 位地址 这是IP协议版本 (简称Ipv )规定的 目前由于IPv 地址已近耗尽 所以IPv 地址正逐渐代替Ipv 地址 Ipv 地址则是 位无符号整数   假设第二个程序被加入图 的网络的Host B中 那么由Host A传来的信息如何能被正确的传给程序B而不是传给新加入的程序呢?这是因为每一个基于TCP/IP网络通讯的程序都被赋予了唯一的端口和端口号 端口是一个信息缓冲区 用于保留Socket中的输入/输出信息 端口号是一个 位无符号整数 范围是 以区别主机上的每一个程序(端口号就像房屋中的房间号) 低于 的短口号保留给标准应用程序 比如pop 的端口号就是 每一个套接字都组合进了IP地址 端口 端口号 这样形成的整体就可以区别每一个套接字t 下面我们就来谈谈两种套接字 流套接字和自寻址数据套接字    流套接字(Stream Socket)  无论何时 在两个网络应用程序之间发送和接收信息时都需要建立一个可靠的连接 流套接字依靠TCP协议来保证信息正确到达目的地 实际上 IP包有可能在网络中丢失或者在传送过程中发生错误 任何一种情况发生 作为接受方的 TCP将联系发送方TCP重新发送这个IP包 这就是所谓的在两个流套接字之间建立可靠的连接   流套接字在C/S程序中扮演一个必需的角色 客户机程序(需要访问某些服务的网络应用程序)创建一个扮演服务器程序的主机的IP地址和服务器程序(为客户端应用程序提供服务的网络应用程序)的端口号的流套接字对象   客户端流套接字的初始化代码将IP地址和端口号传递给客户端主机的网络管理软件 管理软件将IP地址和端口号通过NIC传递给服务器端主机 服务器端主机读到经过NIC传递来的数据 然后查看服务器程序是否处于监听状态 这种监听依然是通过套接字和端口来进行的 如果服务器程序处于监听状态 那么服务器端网络管理软件就向客户机网络管理软件发出一个积极的响应信号 接收到响应信号后 客户端流套接字初始化代码就给客户程序建立一个端口号 并将这个端口号传递给服务器程序的套接字(服务器程序将使用这个端口号识别传来的信息是否是属于客户程序)同时完成流套接字的初始化   如果服务器程序没有处于监听状态 那么服务器端网络管理软件将给客户端传递一个消极信号 收到这个消极信号后 客户程序的流套接字初始化代码将抛出一个异常对象并且不建立通讯连接 也不创建流套接字对象 这种情形就像打电话一样 当有人的时候通讯建立 否则电话将被挂起   这部分的工作包括了相关联的三个类 InetAddress Socket 和 ServerSocket InetAddress对象描绘了 位或 位IP地址 Socket对象代表了客户程序流套接字 ServerSocket代表了服务程序流套接字 所有这三个类均位于包中    InetAddress类  InetAddress类在网络API套接字编程中扮演了一个重要角色 参数传递给流套接字类和自寻址套接字类构造器或非构造器方法 InetAddress描述了 位或 位IP地址 要完成这个功能 InetAddress类主要依靠两个支持类Inet Address 和 Inet Address 这三个类是继承关系 InetAddrress是父类 Inet Address 和 Inet Address是子类   由于InetAddress类只有一个构造函数 而且不能传递参数 所以不能直接创建InetAddress对象 比如下面的做法就是错误的 InetAddress ia = new InetAddress ();  但我们可以通过下面的 个工厂方法创建来创建一个InetAddress对象或InetAddress数组     getAllByName(String host)方法返回一个InetAddress对象的引用 每个对象包含一个表示相应主机名的单独的IP地址 这个IP地址是通过host参数传递的 对于指定的主机如果没有IP地址存在那么这个方法将抛出一个UnknownHostException 异常对象     getByAddress(byte [] addr)方法返回一个InetAddress对象的引用 这个对象包含了一个Ipv 地址或Ipv 地址 Ipv 地址是一个 字节数组 Ipv 地址是一个 字节地址数组 如果返回的数组既不是 字节的也不是 字节的 那么方法将会抛出一个UnknownHostException异常对象     getByAddress(String host byte [] addr)方法返回一个InetAddress对象的引用 这个InetAddress对象包含了一个由host和 字节的addr数组指定的IP地址 或者是host和 字节的addr数组指定的IP地址 如果这个数组既不是 字节的也不是 位字节的 那么该方法将抛出一个UnknownHostException异常对象     getByName(String host)方法返回一个InetAddress对象 该对象包含了一个与host参数指定的主机相对应的IP地址 对于指定的主机如果没有IP地址存在 那么方法将抛出一个UnknownHostException异常对象     getLocalHost()方法返回一个InetAddress对象 这个对象包含了本地机的IP地址 考虑到本地主机既是客户程序主机又是服务器程序主机 为避免混乱 我们将客户程序主机称为客户主机 将服务器程序主机称为服务器主机   上面讲到的方法均提到返回一个或多个InetAddress对象的引用 实际上每一个方法都要返回一个或多个Inet Address/Inet Address对象的引用 调用者不需要知道引用的子类型 相反调用者可以使用返回的引用调用InetAddress对象的非静态方法 包括子类型的多态以确保重载方法被调用   InetAddress和它的子类型对象处理主机名到主机IPv 或IPv 地址的转换 要完成这个转换需要使用域名系统 下面的代码示范了如何通过调用getByName(String host)方法获得InetAddress子类对象的方法 这个对象包含了与host参数相对应的IP地址 InetAddress ia = InetAddress getByName ( ));  一但获得了InetAddress子类对象的引用就可以调用InetAddress的各种方法来获得InetAddress子类对象中的IP地址信息 比如 可以通过调用getCanonicalHostName()从域名服务中获得标准的主机名 getHostAddress()获得IP地址 getHostName()获得主机名 isLoopbackAddress()判断IP地址是否是一个loopback地址   List 是一段示范代码 InetAddressDemo // InetAddressDemo javaimport *;class InetAddressDemo public static void main (String [] args) throws UnknownHostException   String host = localhost ;  if (args length == )   host = args [ ];  InetAddress ia = InetAddress getByName (host);  System out println ( Canonical Host Name = +        ia getCanonicalHostName ());  System out println ( Host Address = +        ia getHostAddress ());  System out println ( Host Name = +        ia getHostName ());  System out println ( Is Loopback Address = +        ia isLoopbackAddress ());   当无命令行参数时 代码输出类似下面的结果 Canonical Host Name = localhostHost Address = Host Name = localhostIs Loopback Address = true   InetAddressDemo给了你一个指定主机名作为命令行参数的选择 如果没有主机名被指定 那么将使用localhost(客户机的) InetAddressDemo通过调用getByName(String host)方法获得一个InetAddress子类对象的引用 通过这个引用获得了标准主机名 主机地址 主机名以及IP地址是否是loopback地址的输出    Socket类  当客户程序需要与服务器程序通讯的时候 客户程序在客户机创建一个socket对象 Socket类有几个构造函数 两个常用的构造函数是 Socket(InetAddress addr int port) 和 Socket(String host int port) 两个构造函数都创建了一个基于Socket的连接服务器端流套接字的流套接字 对于第一个InetAddress子类对象通过addr参数获得服务器主机的IP地址 对于第二个函数host参数包被分配到InetAddress对象中 如果没有IP地址与host参数相一致 那么将抛出UnknownHostException异常对象 两个函数都通过参数port获得服务器的端口号 假设已经建立连接了 网络API将在客户端基于Socket的流套接字中捆绑客户程序的IP地址和任意一个端口号 否则两个函数都会抛出一个IOException对象   如果创建了一个Socket对象 那么它可能通过调用Socket的 getInputStream()方法从服务程序获得输入流读传送来的信息 也可能通过调用Socket的 getOutputStream()方法获得输出流来发送消息 在读写活动完成之后 客户程序调用close()方法关闭流和流套接字 下面的代码创建了一个服务程序主机地址为 端口号为 的Socket对象 然后从这个新创建的Socket对象中读取输入流 然后再关闭流和Socket对象 Socket s = new Socket ( );InputStream is = s getInputStream ();// Read from the stream is close ();s close ();  接下面我们将示范一个流套接字的客户程序 这个程序将创建一个Socket对象 Socket将访问运行在指定主机端口 上的服务程序 如果访问成功客户程序将给服务程序发送一系列命令并打印服务程序的响应 List 使我们创建的程序SSClient的源代码   Listing : SSClient java // SSClient javaimport java io *;import *; class SSClient public static void main (String [] args)   String host = localhost ;  // If user specifies a mand line argument that argument  // represents the host name   if (args length == )   host = args [ ];  BufferedReader br = null;  PrintWriter pw = null;  Socket s = null;  try     // Create a socket that attempts to connect to the server   // program on the host at port    s = new Socket (host );   // Create an input stream reader that chains to the socket s   // byte oriented input stream The input stream reader   // converts bytes read from the socket to characters The   // conversion is based on the platform s default character   // set    InputStreamReader isr;   isr = new InputStreamReader (s getInputStream ());   // Create a buffered reader that chains to the input stream   // reader The buffered reader supplies a convenient method   // for reading entire lines of text    br = new BufferedReader (isr);   // Create a print writer that chains to the socket s byte    // oriented output stream The print writer creates an   // intermediate output stream writer that converts   // characters sent to the socket to bytes The conversion   // is based on the platform s default character set    pw = new PrintWriter (s getOutputStream () true);   // Send the DATE mand to the server    pw println ( DATE );   // Obtain and print the current date/time    System out println (br readLine ());   // Send the PAUSE mand to the server This allows several   // clients to start and verifies that the server is spawning   // multiple threads    pw println ( PAUSE );   // Send the DOW mand to the server    pw println ( DOW );   // Obtain and print the current day of week    System out println (br readLine ());   // Send the DOM mand to the server     pw println ( DOM );   // Obtain and print the current day of month    System out println (br readLine ());   // Send the DOY mand to the server    pw println ( DOY );   // Obtain and print the current day of year    System out println (br readLine ());    catch (IOException e)     System out println (e toString ());    finally     try       if (br != null)     br close ();    if (pw != null)     pw close ();    if (s != null)     s close ();      catch (IOException e)            运行这段程序将会得到下面的结果 Tue Jan : : CST TUESDAY   SSClient创建了一个Socket对象与运行在主机端口 的服务程序联系 主机的IP地址由host变量确定 SSClient将获得Socket的输入输出流 围绕BufferedReader的输入流和PrintWriter的输出流对字符串进行读写操作就变得非常容易 SSClient个服务程序发出各种date/time命令并得到响应 每个响应均被打印 一旦最后一个响应被打印 将执行Try/Catch/Finally结构的Finally子串 Finally子串将在关闭Socket之前关闭BufferedReader 和 PrintWriter   在SSClient源代码编译完成后 可以输入java SSClient 来执行这段程序 如果有合适的程序运行在不同的主机上 采用主机名/IP地址为参数的输入方式 比如是运行服务器程序的主机 那么输入方式就是java SSClient    技巧  Socket类包含了许多有用的方法 比如getLocalAddress()将返回一个包含客户程序IP地址的InetAddress子类对象的引用;getLocalPort()将返回客户程序的端口号;getInetAddress()将返回一个包含服务器IP地址的InetAddress子类对象的引用 getPort()将返回服务程序的端口号    ServerSocket类  由于SSClient使用了流套接字 所以服务程序也要使用流套接字 这就要创建一个ServerSocket对象 ServerSocket有几个构造函数 最简单的是ServerSocket(int port) 当使用ServerSocket(int port)创建一个ServerSocket对象 port参数传递端口号 这个端口就是服务器监听连接请求的端口 如果在这时出现错误将抛出IOException异常对象 否则将创建ServerSocket对象并开始准备接收连接请求   接下来服务程序进入无限循环之中 无限循环从调用ServerSocket的accept()方法开始 在调用开始后accept()方法将导致调用线程阻塞直到连接建立 在建立连接后accept()返回一个最近创建的Socket对象 该Socket对象绑定了客户程序的IP地址或端口号   由于存在单个服务程序与多个客户程序通讯的可能 所以服务程序响应客户程序不应该花很多时间 否则客户程序在得到服务前有可能花很多时间来等待通讯的建立 然而服务程序和客户程序的会话有可能是很长的(这与电话类似) 因此为加快对客户程序连接请求的响应 典型的方法是服务器主机运行一个后台线程 这个后台线程处理服务程序和客户程序的通讯   为了示范我们在上面谈到的慨念并完成SSClient程序 下面我们创建一个SSServer程序 程序将创建一个ServerSocket对象来监听端口 的连接请求 如果成功服务程序将等待连接输入 开始一个线程处理连接 并响应来自客户程序的命令 下面就是这段程序的代码   Listing : SSServer java // SSServer javaimport java io *;import *;import java util *;class SSServer public static void main (String [] args) throws IOException    System out println ( Server starting \\n );   // Create a server socket that listens for ining connection  // requests on port   ServerSocket server = new ServerSocket ( );  while (true)     // Listen for ining connection requests from client   // programs establish a connection and return a Socket   // object that represents this connection    Socket s = server accept ();   System out println ( Accepting Connection \\n );   // Start a thread to handle the connection    new ServerThread (s) start ();   class ServerThread extends Thread private Socket s; ServerThread (Socket s)   this s = s;  public void run ()   BufferedReader br = null;  PrintWriter pw = null;  try     // Create an input stream reader that chains to the socket s   // byte oriented input stream The input stream reader   // converts bytes read from the socket to characters The   // conversion is based on the platform s default character   // set    InputStreamReader isr;   isr = new InputStreamReader (s getInputStream ());   // Create a buffered reader that chains to the input stream   // reader The buffered reader supplies a convenient method   // for reading entire lines of text    br = new BufferedReader (isr);   // Create a print writer that chains to the socket s byte    // oriented output stream The print writer creates an   // intermediate output stream writer that converts   // characters sent to the socket to bytes The conversion   // is based on the platform s default character set    pw = new PrintWriter (s getOutputStream () true);   // Create a calendar that makes it possible to obtain date   // and time information    Calendar c = Calendar getInstance ();   // Because the client program may send multiple mands a   // loop is required Keep looping until the client either   // explicitly requests termination by sending a mand   // beginning with letters BYE or implicitly requests   // termination by closing its output stream    do       // Obtain the client program s next mand     String cmd = br readLine ();    // Exit if client program has closed its output stream     if (cmd == null)     break;      // Convert mand to uppercase for ease of parison     cmd = cmd toUpperCase ();    // If client program sends BYE mand terminate     if (cmd startsWith ( BYE ))     break;    // If client program sends DATE or TIME mand return    // current date/time to the client program     if (cmd startsWith ( DATE ) || cmd startsWith ( TIME ))     pw println (c getTime () toString ());    // If client program sends DOM (Day Of Month) mand     // return current day of month to the client program     if (cmd startsWith ( DOM ))     pw println ( + c get (Calendar DAY_OF_MONTH));    // If client program sends DOW (Day Of Week) mand     // return current weekday (as a string) to the client    // program     if (cmd startsWith ( DOW ))     switch (c get (Calendar DAY_OF_WEEK))         case Calendar SUNDAY : pw println ( SUNDAY );      break;     case Calendar MONDAY : pw println ( MONDAY );      break;     case Calendar TUESDAY : pw println ( TUESDAY );      break;     case Calendar WEDNESDAY: pw println ( WEDNESDAY );      break;     case Calendar THURSDAY : pw println ( THURSDAY );      break;     case Calendar FRIDAY : pw println ( FRIDAY );      break;     case Calendar SATURDAY : pw println ( SATURDAY );        // If client program sends DOY (Day of Year) mand     // return current day of year to the client program     if (cmd startsWith ( DOY ))     pw println ( + c get (Calendar DAY_OF_YEAR));     // If client program sends PAUSE mand sleep for three     // seconds      if (cmd startsWith ( PAUSE ))    try         Thread sleep ( );        catch (InterruptedException e)              while (true);      catch (IOException e)       System out println (e toString ());      finally       System out println ( Closing Connection \\n );    try         if (br != null)      br close ();      if (pw != null)       pw close ();      if (s != null)       s close ();        catch (IOException e)               运行这段程序将得到下面的输出 Server starting Accepting Connection Closing Connection   SSServer的源代码声明了一对类 SSServer 和ServerThread SSServer的main()方法创建了一个ServerSocket对象来监听端口 上的连接请求 如果成功 SSServer进入一个无限循环中 交替调用ServerSocket的 accept() 方法来等待连接请求 同时启动后台线程处理连接(accept()返回的请求) 线程由ServerThread继承的start()方法开始 并执行ServerThread的run()方法中的代码   一旦run()方法运行 线程将创建BufferedReader PrintWriter和 Calendar对象并进入一个循环 这个循环由读(通过BufferedReader的 readLine())来自客户程序的一行文本开始 文本(命令)存储在cmd引用的string对象中 如果客户程序过早的关闭输出流 会发生什么呢?答案是 cmd将得不到赋值   注意必须考虑到这种情况 在服务程序正在读输入流时 客户程序关闭了输出流 如果没有对这种情况进行处理 那么程序将产生异常   一旦编译了SSServer的源代码 通过输入Java SSServer来运行程序 在开始运行SSServer后 就可以运行一个或多个SSClient程序 cha138/Article/program/Java/hx/201311/25867

相关参考

知识大全 C# GDI+编程之基础篇

C#GDI+编程之基础篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一关于GDI+  从本质

知识大全 浅析C#中的套接字编程

浅析C#中的套接字编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!大家都知道Java语言的强大功

知识大全 Java多线程编程基础之线程对象

Java多线程编程基础之线程对象  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &nbs

知识大全 实战体会Java多线程编程精要之基础

实战体会Java多线程编程精要之基础  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &n

知识大全 Java多线程编程基础之线程和多线程

Java多线程编程基础之线程和多线程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  随着计算机技

知识大全 关于java中的对象序列化

  java对象序列化机制一般来讲有两种用途      需要将对象的状态保存到文件中而后能够通过读入对象状态来重新构造对象恢复程序状态      使用套接字在网络上传送对象的程序来说是很有用的    

知识大全 一篇不错的介绍Java Socket编程的文章

一篇不错的介绍JavaSocket编程的文章  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  事实

知识大全 套接字编程介绍

  套接字(socket)是网络计算机与应用程序之间发送和接收数据的方式的一种抽象描述它描述了(可能在不同的计算机上也可能在同一台计算机内的)两个通信点之间的连接  在实际操作中套接字编程往往与TCP

知识大全 在 WAS 中使用 Java 安全套接字扩展(图)

在WAS中使用Java安全套接字扩展(图)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  本文提

知识大全 Java设计模式之修饰模式篇

Java设计模式之修饰模式篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  最近我给女朋友买了一