选择显示字体大小

java套接字实现网络编程之基础篇(1)

java开发网络软件非常方便和强大,java的这种力量来源于他独有的一套强大的用于网络的 api,这些api是一系列的类和接口,均位于包java.netjavax.net中。在这篇文章中我们将介绍套接字(socket)慨念,同时以实例说明如何使.network api操纵套接字,在完成本文后,你将具备编写网络低端通讯软件的能力。

什么是套接字(socket)?



.network api是典型的用于基于tcp/ip网络java程序与其他程序通讯.network api依靠socket进行通讯。socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入socket中,该socket将这段信息发送给另外一个socket中,使这段信息能传送到其他程序中。如图1

我们来分析一下图1,host a上的程序a将一段信息写入socket中,socket的内容被host a的网络管理软件访问,并将这段信息通过host a的网络接口卡发送到host b,host b的网络接口卡接收到这段信息后,传送给host b的网络管理软件,网络管理软件将这段信息保存在host b的socket中,然后程序b才能在socket中阅读这段信息。

假设在图1的网络中添加第三个主机host c,那么host a怎么知道信息被正确传送到host b而不是被传送到host c中了呢?基于tcp/ip网络中的每一个主机均被赋予了一个唯一的ip地址,ip地址是一个32位的无符号整数,由于没有转变成二进制,因此通常以小数点分隔,如:198.163.227.6,正如所见ip地址均由四个部分组成,每个部分的范围都是0-255,以表示8位地址。

值得注意的是ip地址都是32位地址,这是ip协议版本4(简称ipv4)规定的,目前由于ipv4地址已近耗尽,所以ipv6地址正逐渐代替ipv4地址,ipv6地址则是128位无符号整数。

假设第二个程序被加入图1的网络的host b中,那么由host a传来的信息如何能被正确的传给程序b而不是传给新加入的程序呢?这是因为每一个基于tcp/ip网络通讯的程序都被赋予了唯一的端口和端口号,端口是一个信息缓冲区,用于保留socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的短口号保留给标准应用程序,比如pop3的端口号就是110,每一个套接字都组合进了ip地址、端口、端口号,这样形成的整体就可以区别每一个套接字t,下面我们就来谈谈两种套接字:流套接字和自寻址数据套接字。

流套接字(stream socket

无论何时,在两个网络应用程序之间发送和接收信息时都需要建立一个可靠的连接,流套接字依靠tcp协议来保证信息正确到达目的地,实际上,ip包有可能在网络中丢失或者在传送过程中发生错误,任何一种情况发生,作为接受方的 tcp将联系发送方tcp重新发送这个ip包。这就是所谓的在两个流套接字之间建立可靠的连接。

流套接字在c/s程序中扮演一个必需的角色,客户机程序(需要访问某些服务的网络应用程序)创建一个扮演服务器程序的主机的ip地址和服务器程序(为客户端应用程序提供服务的网络应用程序)的端口号的流套接字对象。

客户端流套接字的初始化代码将ip地址和端口号传递给客户端主机的网络管理软件,管理软件将ip地址和端口号通过nic传递给服务器端主机;服务器端主机读到经过nic传递来的数据,然后查看服务器程序是否处于监听状态,这种监听依然是通过套接字和端口来进行的;如果服务器程序处于监听状态,那么服务器端网络管理软件就向客户机网络管理软件发出一个积极的响应信号,接收到响应信号后,客户端流套接字初始化代码就给客户程序建立一个端口号,并将这个端口号传递给服务器程序的套接字(服务器程序将使用这个端口号识别传来的信息是否是属于客户程序)同时完成流套接字的初始化。

如果服务器程序没有处于监听状态,那么服务器端网络管理软件将给客户端传递一个消极信号,收到这个消极信号后,客户程序的流套接字初始化代码将抛出一个异常对象并且不建立通讯连接,也不创建流套接字对象。这种情形就像打电话一样,当有人的时候通讯建立,否则电话将被挂起。

这部分的工作包括了相关联的三个类:.netaddress, socket, 和 serversocket.netaddress对象描绘了32位或128位ip地址,socket对象代表了客户程序流套接字,serversocket代表了服务程序流套接字,所有这三个类均位于包java.net中。

.netaddress类

.netaddress类在网络api套接字编程中扮演了一个重要角色。参数传递给流套接字类和自寻址套接字类构造器或非构造器方法。.netaddress描述了32位或64位ip地址,要完成这个功能,.netaddress类主要依靠两个支持类.net4address 和 .net6address,这三个类是继承关系,.netaddrress是父类,.net4address 和 .net6address是子类。

由于.netaddress类只有一个构造函数,而且不能传递参数,所以不能直接创建.netaddress对象,比如下面的做法就是错误的:

.netaddress ia = new .netaddress ();

但我们可以通过下面的5个工厂方法创建来创建一个.netaddress对象或.netaddress数组:

 . getallbyname(string host)方法返回一个.netaddress对象的引用,每个对象包含一个表示相应主机名的单独的ip地址,这个ip地址是通过host参数传递的,对于指定的主机如果没有ip地址存在那么这个方法将抛出一个unknownhostexception 异常对象。

 . getbyaddress(byte [] addr)方法返回一个.netaddress对象的引用,这个对象包含了一个ipv4地址或ipv6地址,ipv4地址是一个4字节数组,ipv6地址是一个16字节地址数组,如果返回的数组既不是4字节的也不是16字节的,那么方法将会抛出一个unknownhostexception异常对象。

 . getbyaddress(string host, byte [] addr)方法返回一个.netaddress对象的引用,这个.netaddress对象包含了一个由host和4字节的addr数组指定的ip地址,或者是host和16字节的addr数组指定的ip地址,如果这个数组既不是4字节的也不是16位字节的,那么该方法将抛出一个unknownhostexception异常对象。

 . getbyname(string host)方法返回一个.netaddress对象,该对象包含了一个与host参数指定的主机相对应的ip地址,对于指定的主机如果没有ip地址存在,那么方法将抛出一个unknownhostexception异常对象。

 . getlocalhost()方法返回一个.netaddress对象,这个对象包含了本地机的ip地址,考虑到本地主机既是客户程序主机又是服务器程序主机,为避免混乱,我们将客户程序主机称为客户主机,将服务器程序主机称为服务器主机。

上面讲到的方法均提到返回一个或多个.netaddress对象的引用,实际上每一个方法都要返回一个或多个.net4address/.net6address对象的引用,调用者不需要知道引用的子类型,相反调用者可以使用返回的引用调用.netaddress对象的非静态方法,包括子类型的多态以确保重载方法被调用。

.netaddress和它的子类型对象处理主机名到主机ipv4或ipv6地址的转换,要完成这个转换需要使用域名系统,下面的代码示范了如何通过调用getbyname(string host)方法获得.netaddress子类对象的方法,这个对象包含了与host参数相对应的ip地址:

.netaddress ia = .netaddress.getbyname ("www.javajeff.com"));

一但获得了.netaddress子类对象的引用就可以调用.netaddress的各种方法来获得.netaddress子类对象中的ip地址信息,比如,可以通过调用getcanonicalhostname()从域名服务中获得标准的主机名;gethostaddress()获得ip地址,gethostname()获得主机名,isloopbackaddress()判断ip地址是否是一个loopback地址。

list1 是一段示范代码:.netaddressdemo

// .netaddressdemo.java

import java.net.*;

class .netaddressdemo

{

 public static void main (string [] args) throws unknownhostexception

 {

string host = "localhost";

if (args.length == 1)

 host = args [0];

.netaddress ia = .netaddress.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 = localhost

host address = 127.0.0.1

host name = localhost

is loopback address = true

.netaddressdemo给了你一个指定主机名作为命令行参数的选择,如果没有主机名被指定,那么将使用localhost(客户机的),.netaddressdemo通过调用getbyname(string host)方法获得一个.netaddress子类对象的引用,通过这个引用获得了标准主机名,主机地址,主机名以及ip地址是否是loopback地址的输出。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons