Java----网络编程初解
前面学习到Java是一种与平台无关的编程语言,具有“一次编写,到处运行”的特点,所以出现了非常适应Java的网络编程。可以说在网络编程方面,没有任何一门语言比Java更优秀。
1、了解网络基础
在开始学习网络编程前,先来学习网络的一些内容。这些内容有的已经超出了Java的内容,但是要先了解这些内容,使它们在Java中更好地应用。
1)、TCP/IP协议的认识
TCP/IP协议集是计算机网络中使用最广泛的体系结构之一,它是为互联网络设计的。该协议是以TCP和IP为基础的所有相关协议的集合。应用层有SMTP(简单邮件传输协议)、NNTP(网络新闻传输协议)和HTTP(超文本传输协议),HTTP也就是平时上网看网页用的协议,它们是通信所遵循的规则。
IP协议是一种数据报文协议,它的作用是通过IP来找到网络中的位移主机。
TCP协议是Tranfer ContrlProtocol的简称,是一个面向连接的、保证可靠传输的数据流服务的协议。通过TCP协议传输,得到的是一个顺序的、无差错的数据流。客户端和服务器端的两个成对的Socket之间必须建立相应连接,以此为基础通过TCP协议进行通信,当一个Socket等待建立连接时,另一个Socket可以要求进行连接,两个Socket连接起来后,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。由于TCP协议是面向连接的协议,因此在通过Socket传输之前必须建立连接。
2)、URL的使用
在讲解URL之前,先来看一下网络IP地址。每台机器都有一个与众不同的IP地址,它是为了实现网络中不同计算机之间的通信而设置的,使每个机器有不一样的标识。IP地址格式如192.168.0.0一样,由4个8位的二进制数组成,每8位之间用原点隔开。
在这里需要提到的还有DNS(域名系统)。服务器是需要通过IP地址来进行访问的,但平常上网时,只是输入如www.baidu.com这样的网址,那么就需要用到DNS。DNS的作用是将平常输入的文本网络地址转换成难懂但很高效的网络地址。这是网络发展的重要一步,因为人更容易记住文本形式的地址,但对于服务器来说,它执行数字地址要比文本地址快得多。
接下来讲解URL这个重要话题。URL是Uniform Resource Locator的缩写,是同意资源定位器的简称,它表示Internet上某一资源的地址。通过URL可以访问Internet上的各种网络资源,如最常见的WWW、FTP站点。浏览器通过解析给定的URL可以在网络上访问相应的文件或其他资源。
URL是由协议名和资源名组成的,基本形式如protocl://resourceName。协议名(protocol)指明获取资源所使用的传输协议,如HTTP、FTP、GOPHER、FILE等;资源名(resourceName)则应该是所要访问资源的完整地址,它是由能转换成主机名的文本地址或直接指定多访问服务器的端口、文件名或文件内部的一个引用所组成的。如http://www.baidu.com/是有协议名加主机名组成的;而http://home.netscape.com/home/welcome.html则是由协议名加主机名加文件名组成的。
在Java中有一个URL类,它存在java.net包中。URL类时网络编程的一项重要内容,它为Java访问网络资源提供了接口,通过这些接口可以很容易地访问服务器上的文件和应用程序,及获得一个远程对象实例。URL类的构造方法有如下4种:
>public URL(String spec):通过一个表示URL地址的字符串可以构造一个URL对象。如URL u1 = new URL(“http://www.baidu.com”);
>public URL(URL context ,String spec):通过基URL和相对URL指定文件构造一个URL对象,如URL u2 = new URL(u1 , “index.html”);
>public URL(Stringprotocol , String host , String file):通过协议名、主机名和相对URL指定文件狗仔一个URL对象,如URLu3 = new URL(“http”,www.baidu.com”,”download/index.html);
>public URL(Stringprotocol , String host , String port , String file):通过协议名、主机名、端口号和相对URL指定文件构造一个URL对象,如URL u4 = new URL(“http”,www.baidu.com , 8080, “download/index.html”)。
下面是一个关于URL类使用的实例,使用URL类时可能会抛出异常,需提前将异常情况解决:
public class test {
public static void main(String[] args){
try {
//构造URL类
URL url = newURL("http://www.baidu.com");
} catch (MalformedURLException e) {
System.out.println(e);
} catch (IOException ee) {
System.out.println(ee);
} catch (Exception eee) {
System.err.println(eee);
}
}
}
在URL的API中,定义了很多方法来获得这些属性,这里列出了一些经常用到的方法,具体如下:
>public StringgetProtocl():获取该URL的协议名
>public String getHost():获取该URL的主机名
>public int getPort():获取该URL的端口号,如果没有设置端口,返回-1
>public String getFile():获取该URL的文件名
>public String getRef():获取该URL在文件中的相对位置
>public String getQuery():获取该URL的查询信息
>public String getPath():获取该URL的路径
>public StringgetAuthority():获取该URL的权限
>public StringgetUserInfo():获得试用这的信息
调用URL类中的方法:
public class test {
public static void main(String[] args)throws MalformedURLException{
URL url = newURL("http://www.baidu.com");
System.out.println(url.getProtocol() +"1");
System.out.println(url.getHost() +"2");
System.out.println(url.getPort() +"3");
System.out.println(url.getFile() +"4");
}
}
URL类中有一个openStream()方法,通过它可以访问网络。这里需要结合前面所学到的I/O流知识来进行学习。
2、网络编程步骤
网络编程大致分为4步:第一步是创建Socket;第二部是打开连接到Socket的输入流和输出流;第三步是对Socket进行读写操作;最后一步就是关闭Socket。从中可以看到网络编程主要是通过Socket完成的,所以下面会详细讲解Socket。
1)、使用Socket进行网络连接
Socket通过网络中的IP和端口用来指出其中的某一台计算机。上面已经提到网络通信中有一些通信协议,如网络层的IP协议,传输层的TCP、UDP协议,应用层的HTTP协议。Socket就是将这些协议联系到一起,从而能向网络中其他主机发送信息,主机也能回答信息。
在Java的网络编程中,一个Socket由主机号、端口号和协议名3部分组成。主机号不但可以连接网络计算机的IP地址,而且也能连接翻译成IP地址的文本地址,它在网络中是唯一的。
端口号是计算机内部的一个抽象事物。通常服务器中有很多客户程序,当有网络信息传入后,不能很快选择客户程序,这时就需要端口号来指明客户程序。也就是说在尽兴网络通信时,必须指出客户端和服务器端都认可的端口。在编写程序时通常要选用大于1024的端口号,小于1024的端口有可能被操作系统给保留了,如果在使用就会产生错误。
协议名是指计算机之间建立连接、完成数据通信所采用的协议名称。在Java中,Socket是使用面向连接的协议。Socket类表示TCP协议,DatagramSocket类表示UDP协议。
2)、创建Socket
在java.net包中定义了Socket和ServerSocket两个雷,Socket类表示客户端或者服务器端Socket连接的两端,ServerSocket表示服务器端等待来自客户端的连接。通过Socket建立连接,首先服务器要建立监听线程,负责监听服务器程序指定的端口,等待客户端的连接。然后是客户端创建一个Socket对象,其中要指明要连接主机的IP地址和端口号及使用的通信协议,创建Socket对象的同时,发送连接服务器的请求。最后就是服务器端接收请求,建立通信。Socket的构造方法有:
>Socket(InetAddressaddress , int port)
>Socket(InetAddressaddress , int port , Boolean stream)
>Socket(String host , intport)
>Socket(String host , intport , Boolean stream)
>Socket(SocketImpl impl)
>Socket(String host , intport , InetAddress localAddr , int localPort)
>Socket(InetAddressaddress , int port , InetAddress localAddr , int llocalPort)
其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号,stream指明Socket是流Socket还是数据报Socket,localPort表示本地主机的端口号,localAddr是本地机器的地址(ServerSocket的主机地址),impl是Socket的父类,既可以用来创建ServerSocket又可以用来创建Socket。
ServerSocket的构造方法有:
>ServerSocket(int port)
>ServerSocket(int port ,int backlog)
>ServerSocket(int port ,int backlog , InetAddress bindAddr)
其中bindAddr也表示本地机器的地址。
3)、服务器端的访问
在服务器端首先要建立监听,通常是通过ServerSocket类来完成服务器端监听,同时还可以接收客户端发送的数据。ServerSocket类的几种形式的构造器在前面已经讲过。在服务器端建立监听和等待机制后,当客户端需要建立一个连接时,服务器端就会调用本身的一个accept()方法来返回一个服务器端的Socket对象,这样即可直接进行通信。步骤概括如下:
>创建ServerSocket对象同时建立监听;
>调用accept()方法获得新的Socket连接;
>通过新的Socket对象获得流对象;
>通过协议,和客户端进行通信;
>关闭客户端流和相应Socket对象;
>关闭ServerSocket对象。
下面是对服务器端进行访问的代码:
public class mytest01 {
public static void main(String[] ags){
try {
//创建一个ServerSocket对象
ServerSocket ss = newServerSocket(2013);
while (true) {
//接收Socket
Socket s = ss.accept();
//运用IO流知识
InputStream is =s.getInputStream();
OutputStream os =s.getOutputStream();
InputStreamReader isr = newInputStreamReader(is);
BufferedReader br = newBufferedReader(isr);
//获取客户端发送信息
String request = br.readLine();
System.out.println(request);
PrintStream ps = newPrintStream(os);
ps.println("Bye");//返回信息
s.close();
ss.close();
}
} catch (Exception e) {
System.err.println(e);
}
}
}
运行程序在没有客户端的情况下,没有任何内容。在本服务器端程序中,首先建立了一个端口号为2013的ServerSocket对象,然后调用accept方法等待客户端请求,当有客户端请求后,就会创建一个Socket对象。接下来即可进行输出和输入的通信。最后调用close()方法关闭连接。运行结果为空表明等待连接。
4)、客户端的访问
客户端相对服务器端容易一些,它只需要在服务器端开始监听之后,向服务器端发送请求实例化一个Socket类的对象构造Socket。面向连接的Socket操作使用的是TCP协议。关于TCP协议的说明,可以在前面查到。进行客户端的访问的代码如下:
public class mytest02 {
public static void main(String[] args){
try{
//定义一个Socket对象117.35.142.199
Socket s = newSocket("117.35.142.199" , 2013);
//运用IO流
InputStream is =s.getInputStream();
OutputStream os =s.getOutputStream();
PrintStream ps = newPrintStream(os);
//向服务器发送信息
ps.println("hello");
//获取服务器返回的信息
InputStreamReader isr = newInputStreamReader(is);
BufferedReader br = newBufferedReader(isr);
String request = br.readLine();
System.out.println(request);
s.close();
} catch (Exception e) {
System.err.println(e);
}
}
}
首先运行服务器,然后运行该程序,会看到运行结果在服务端的输出结果为java.net.SocketException:Socket is closed!这是因为我们在服务端的代码中加入了接到访问之后关闭ServerSocket的命令,即ss.slose()。因为是网络编程,所以一定要注意异常处理。客户端和服务端一样,在程序的最后也需要关闭连接。
5)、多客户端连接
上面的程序只实现了Server和一个客户的对话,而在实际应用中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,提供相应的服务。为了实现在服务器给多个客户提供服务的功能,需要修改一下上面的程序,这里利用多线程来实现多客户调用。和前面一样,服务器总是在指定的端口上监听是否有客户请求,这时服务器就会启动一个专门的服务器线程来响应该客户的请求,同时服务器本身在启动完线程之后马上又进入监听状态。等待下一个客户的到来,从而实现了多客户端的连接。因为客户单都一样,只是数量的变化。下面的程序将讲解如何进行多客户端连接。
Public class test01{
public static void main(String[] args){
boolean connected = true;
try{
//定义一个ServerSocket对象
ServerSocket ss = newServerSocket(2013);
Int clientNum = 0;
//一直接收
while(connected){
ServerThread st = new ServerThread(ss.accept(), clientNum);
st.start();
clientNum++;
System.out.println(clientNum);
}
} catch (Exceptione){ System.out.println(“异常” + e); }
}
}//创建多线程
class ServerThread extendsThread{
private Socket s;
int clientNum;
public ServerThread(Socket s , int num){
this.s = s;
clientNum = num;
}
public voidrun(){
try{
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
InputStreamReader isr = newInputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String request = br.readLine();
System.out.println(request);
PrintStream ps = new PrintStream(os);
Ps.println(“Bye”);
s.close();
} catch (Exceptione){ System.out.println(“异常” + e); }
}
}
6)、网络编程综合案例
最后对网络编程进行一下总结。一般而言,网络编程需要有两个程序:一个是服务器端程序,另一个是客户端程序。Java中的网路编程主要是围绕Socket来进行的,在服务器端需要建立一个ServerSocket开发一个端口,以对客户端进行服务;在客户端需要建立一个Socket来通过IP和服务器端开放的端口来访问服务器端。下面给出一个关于网络编程的综合案例,由于源码太大,我上传到资源页大家可以自行下载:
下载页面:http://download.csdn.net/detail/zhai56565/5260911