java网络编程

------------- android培训java培训、java博客、java学习型技术博客、期待与您交流! --------------

网络编程:
网络协议与TCP/IP,TCP/IP是目前网络应用程序的首选协议。
我们现在所学的网络编程也是基于TCP/IP协议的。
编写基于基于TCP/IP协议的网络程序,必须先了解两个重要的概念:IP地址和Port(端口号)
IP地址占用4个字节,Port是一个占用两个字节的整数(范围在0~65535之间,0~1023之间的端口数是用于一些知名的网络服务和应用)。
本地回路IP地址是127.0.0.1
在TCP/IP协议栈中有两个高级协议是网络应用程序编写应该了解的协议。分别是UDP与TCP
TCP:传输控制协议(Transmission Control Protocol),是面向连接的通信协议。在正式通信之前必须先与对方建立连接。可靠性较好。
UDP:用户数据报协议(User Datagram Protocol),是无连接的通信协议。在正式通信之前不必与对方先建立连接,直接通过数据报传输数据。可靠性较差。

TCP,UDP的数据帧格式简单图例: 协议类型--源IP--目标IP--源端口--目标端口--帧序号--帧数据

Socket是网络驱动层提供给应用程序编程的接口和一种机制。

Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和Port。

Socket数据发送过程:(图例)
        
 应用程序-(1)----(产生Socket)----|
            |  |                        |
           (2) (应用程序将要            |
     | 发送的数据传送            |
     | 给Socket)                 |
     |  |                        |
     |  |----(3)------------- Socket
     |                           |
     (调用bind将Socket                  |
     的信息通知给驱动                  (4)
     程序,其中包括                     |
     IP和Port)               (驱动程序从Socket取出数据
     |               并通过网卡发送出去,就是打包成
     |              上面所说的数据帧格式,逐帧的发送。)
     |                           |
 驱动程序------------------------|


Socket数据接收过程:(图例)
        
 应用程序-(1)----(产生Socket)----|
            |  |                        |
           (2) (应用程序从              |
     |   Socket中取出数据)       |
     |  |                        |
     |  |                        |
     |  |----(4)------------- Socket
     |                           |
     (调用bind将Socket                  |
     的信息通知给驱动                  (3)
     程序)                              |
            |               (驱动程序根据从网卡传送过来的
            |                数据报中的指定目标端口号,将
            |                处理后的数据传送到相应的Socket中)
     |                           |
 驱动程序------------------------|

 


java中的网络编程类都位于java.net包中。

DatagramSocket类用于UDP通信。
ServerSocket类用于TCP通信的服务器端。
Socket类用于TCP通信的服务器和客户端。

 


DatagramSocket类有三个主要构造函数:
DatagramSocket():如果UDP程序不用事先接收对方发送的数据,而是主动先给对方发送数据,那最好就用这个构造函数来创建对象。
系统会自动将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port):如果UDP程序有可能先接收别人发送的数据,那就必须得用这个构造函数来创建对象。
DatagramSocket(int port, InetAddress laddr):如果UDP程序要在有多个IP地址的计算机上运行,那么就得用这个构造函数来创建对象。

DatagramSocket类中的方法close()关闭此数据报套接字并通知驱动程序释放与此对象所关联的资源。
DatagramSocket类中的方法send(DatagramPacket p)从此套接字发送UDP数据报包。
DatagramSocket类中的方法receive(DatagramPacket p)从此套接字接收UDP数据报包。

DatagramPacket类相当于一个集装箱,有两个主要构造函数:
DatagramPacket(byte[] buf, int length):创建用来接收数据的DatagramPacket对象。
DatagramPacket(byte[] buf, int length, InetAddress address, int port):创建用来发送数据的DatagramPacket对象。其中buf就是要发送的数据的字节数组。

DatagramPacket类中的方法getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
DatagramPacket类中的方法getPort()返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
DatagramPacket类中的方法getData()返回数据缓冲区。
DatagramPacket类中的方法getLength()返回将要发送或接收到的数据的长度。


InetAddress是用于表示计算机IP地址的一个类。
InetAddress类中的静态方法getByName(String host)根据字符串格式的计算机地址来返回一个相应的InetAddress对象。
InetAddress类中的方法getHostAddress()返回 IP 地址字符串(以文本表现形式)。


UDP接收程序必须先启动运行,才能接受UDP发送程序发送的数据。

看一个最简单的UDP程序:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPSend {

 public static void main(String[] args) throws Exception {

  DatagramSocket ds = new DatagramSocket();
  String message = "hello 黑马  www.csdn.net";
  ds.send(new DatagramPacket(message.getBytes(), message.getBytes().length, 
    InetAddress.getByName("127.0.0.1"), 3000));
  ds.close();
 }
}


import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceive {

 public static void main(String[] args) throws Exception {

  DatagramSocket ds = new DatagramSocket(3000);
  byte[] buf = new byte[1024];
  DatagramPacket dp = new DatagramPacket(buf, 1024);
  ds.receive(dp);
  System.out.println(new String(dp.getData(), 0, dp.getLength()));
  System.out.println("address: " + dp.getAddress().getHostAddress()
      + "  port: " + dp.getPort());
  ds.close();
 }
}

 


如何发送广播数据?当我们把数据发送到广播地址(假如是:192.168.0.255)的时候,就表示把数据发送到(承上所假如:192.168.0.*)下的所有用户。
不过只有UDP程序才能够发送和接收广播地址的数据。

对于IP地址为192.168.0.123这台计算机所在的广播地址不一定就是192.168.0.255。这需要结合计算机的子网掩码来计算,假如你的子网掩码是255.255.254.0,
那么这台计算机所对应的广播地址应该是:192.168.1.255。

私有IP通过网关代理上网的原理:
假如有一个使用私有IP地址的内部网络,这个内部网络中的计算机不能与internet网络上的计算机按照正常的路由方式进行通信,
因为内部网络上的计算机不具有合法有效的internet的IP地址,也没有连接到internet上的路由设备,在内部网络中有一台计算机除了能跟内部网络的连接外,
还具有与internet网络的连接,具有合法有效的IP地址。如果这台计算机打开了IP网络数据转发功能,或者是安装了具有相应功能的软件,
那么这个内部网络中的其他计算机只要将他们的网关地址设置为与internet网络具有连接的那台计算机的内部网络的IP地址。
就可以借助这台计算机访问internet网络上的计算机了。那么具有与internet网络具有连接的那台计算机就称为这个内部网络的网关。
当内部网络的计算机要访问不属于这个内部网络的IP地址的时候,计算机中的TCP/IP协议模块就会将数据发送到网关上,然后再由网关发送出去,
所以内部网络中的计算机无法将数据直接发送到内部网络以外的网络设备上。


我们分析一下内部网络中的使用私有IP的计算机是如何使用网关来访问internet网络上的计算机的。
假如内部网络中有一台计算机IP为192.168.0.3,需要访问internet网络上IP为221.101.121.57计算机,
那么计算机所发送的数据报包的形式应该是:(如下图)
  ----------------------------------------------------------------
  | 192.168.0.3  |  221.101.121.57  |  3000  |  3000   |  hello  |
  ----------------------------------------------------------------
    (源IP地址)       (目标IP地址)    (源端口) (目标端口)  (数据)
由于源IP和目标IP不属于同一个网络,那么源IP所在的计算机的TCP/IP协议模块就会将这个数据报包发送给网关所绑定的网络设备上,
网关从数据报包中的目标IP地址上就可以知道这个数据需要经过这里转发的,
网关就用(由于网关有一个在internet网络上具有合法有效的IP地址,假如是:166.111.111.10)这个IP地址所对应的网络设备向internet网络发送出去。
发送数据的时候,数据源是以166.111.111.10的身份来发送的。在向外发送数据之前,网关要修改数据报包中的源IP地址和源端口号,
也就是将源数据报包中的源IP地址修改为166.111.111.10, 将3000修改为1027(假如),然后通过166.111.111.10所对应的网络设备将修改后的数据报包发送出去。

(私有IP通过网关代理上网的原理详细请看java基础\10.传智播客JAVA高级视频05_网络编程\传智播客JAVA高级视频05_网络编程\JAVA高级04_04视频)

 


TCP客户端程序与TCP服务器端程序的交互过程:
1,服务器程序创建一个ServerSocket,然后调用accept()方法等待客户端来连接;
2,客户端程序创建一个Socket并请求与服务器建立连接;
3,服务器接收客户端的连接请求,并创建一个新的Socket与该客户端建立专线连接;
4,建立了连接的两个Socket在一个单独的线程(由服务器程序创建)上对话;
5,服务器开始等待新的连接请求,当新的连接请求到达时,重复步骤2到步骤5的过程。

当我们为需要指定端口的对象指定端口的时候一定要注意不能使用已经被别的程序占用了的端口,否则程序将不能正常的运行。


我们每次编写完服务器程序以后,都没有必要马上编写一个客户端程序来对它进行测试,Windows自带的telnet程序就是一个简单实用的TCP客户端程序。
我们可以直接使用telnet程序来测试服务器。只要在运行telnet程序的时候指定所要连接服务器程序的IP地址和端口号。telnet程序就会与这个服务器
建立连接,连接建立以后,在telnet程序窗口中就会显示出服务器端发送过来的数据。而在telnet窗口中用键盘输入的内容都会被发送到服务器端。

连接形式:telnet IP号 端口号

一般情况下我们在telnet窗口中输入的字符不会显示出来,这时我们需要打开telnet程序的本地回显功能,方法如下:
先直接运行telnet命令,进入telnet的命令窗口中,然后输入help,我们就可以查看telnet内部可使用的命令,我们可以看到有一个命令是set,
然后我们输入set ? 看能设什么值,分别又代表什么,我们可以看到LOCAL_ECHO就是打开本地的回显功能。
这时我们就可以输入set LOCAL_ECHO 这样就打开了telnet的本地回显功能,此时用quit退出telnet命令窗口,再执行 telnet IP号 端口号  
这时我们在telnet窗口中输入的字符就可以显示出来了,当我们按回车键的时候就会把内容发送到所连接的服务器上。

 


使用netstat命令查看当前正在被使用的TCP端口号。netstat -help可以查看使用帮助。

我们最好通过一个配置参数来指定TCP服务程序所使用的端口号。

 

我们还可以在TCP网络连接上传递对象。
ObjectInputStream和ObjectOutputStream可以从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。
使用ObjectInputStream和ObjectOutputStream来包装底层网络字节流,TCP服务器和TCP客户端之间就可以传递对象类型的数据。


其实很多应用程序协议都是基于TCP网络通信协议的,比如HTTP协议,FTP协议,STMP协议,POP3协议等。

 

 


访问internet网络资源主要的类有java.net包中的URL,URLDecoder,URLEncoder,URLConnection,HttoURLConnection等类。

URI(Uniform Resource Identifier)表示统一资源标识符。

URL(Uniform Resource Locator)表示统一资源定位符,用于表示internet网络资源的地址。网络资源可以是一个文件,一个目录,或者是一个复杂的对象。
URL的基本组成:协议、主机名、端口号、资源名。如:http://www.it315.org:8080/index.html

在Java中,URI类不包含用于访问通用资源标识符设定的任何方法,它的唯一作用是进行分析。相反,URL类则可以打开到达资源的一个字符串。

HTTP协议定义了web浏览器和web服务器之间交换数据的会话过程以及数据本身的格式。
我们可以简单的认为HTTP协议规定了浏览器从3W服务器上获取网页文件的方式。

URL中的端口号部分用来指定客户端程序要连接的网络服务器程序的监听端口号,每一种标准的网络协议都有一个默认的端口号,
HTTP协议的默认端口号就是80,如果某种协议的服务器程序使用的监听端口号是默认端口号,那么在连接网络服务器的时候URL中就可以不指定端口号,
客户端程序就会使用协议的默认端口号去连接网络服务器。


一个完整的URL可以由一个基准URL和一个相对URL组合而成。
基准URL就是当前网页所在的目录路径;
相对URL的表示:
/a.html-------以/开头表示主机上的某种协议的根目录。
../a.html-------以../开头表示当前资源所在目录的父目录。
a.html或者./a.html-------直接使用文件名、目录名或者以./开头则表示当前资源目录下的文件或者子目录。

 

浏览器访问3W服务器上的网页文件时,需要使用HTTP协议进行通信,在HTTP协议中,浏览器不能向服务器直接传送某些特殊的字符,必须对这些字符进行URL编码后再传送。
URL编码规则:
将空格转换为加号(+);
对0~9,a~z,A~Z之间的字符保持不变;
对于所有其他的字符,用这个字符的当前字符集编码在内存中的十六进制格式表示,并在每个字节前加上一个百分号(%)。如:字符“+”用%2B表示,字符“=”用%3D表示,
字符“&”用%26表示,每个中文字符在内存中占两个字节,字符“中”用%D6%D0表示,字符“国”用%B9%FA表示。
对于空格也可以直接使用其十六进制的编码方式,而不是将它转换成加号(+)。

java.net包中提供了URLEncoder和URLDecoder这两个类,来实现URL编码和解码。


HTTP消息分为请求消息和响应消息。

HTTP请求消息:一个完整的请求消息包括:一个请求行、若干个消息头、以及实体内容。
例如:
GET /articles/news/today.asp HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Connection: Keep-Alive
Host: localhost
Referer: http://localhost/links.asp
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727;
                                                     .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; MALC; TheWorld)
Accept-Encoding: gzip, deflate

(请求消息中的第一行就是请求行,后面紧跟的内容(直到一个空行跟实体内容分隔)都属于消息头部分,消息头和实体内容是可选的,消息头和实体内容要用空行隔开)

 

HTTP响应消息:一个完整的响应消息包括:一个状态行、若干个消息头、以及实体内容。
例如:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 13 Jul 2000 05:50:53 GMT
Content-Length: 2291
Content-Type: text/html
Set-Cookie: ASPSESSIONIDQQGGGNCG=LKLDFFKCINFLDMFHCBCBMFLJ;path=/
Cache-control: private

<html>
<head>
......

(响应消息中的第一行就是状态行,后面紧跟的内容(直到一个空行跟实体内容分隔)都属于消息头部分,消息头和实体内容也是可选的,消息头和实体内容要用空行隔开)


HTTP消息中的消息头是用来描述这个HTTP消息中的一些特性,这种用来描述信息的信息被称为元信息。

了解几个HTTP消息头:
Connection: 用于指定处理完本次请求/响应后,客户端与服务器是否继续保持连接,设置值可以为Keep-Alive和close。默认是Keep-Alive。
Accept-Language: 用于指定客户机期望服务器返回的文档所使用的国家语言,可以指定多个以逗号分隔的国家语言。
Content-Length: 用于表示实体内容的长度(字节数)。
Range: (请求消息头)用于指定服务器只需返回文档中的部分内容及内容范围,有以下几种使用格式。
        (1)Range: bytes=100-599        表示只返回从第100个字节到第599个字节之间的内容,包括第100个字节和第599个字节,字节的顺序是从0开始计算。
 (2)Range: bytes=100-           表示请求服务器只返回第100个字节以后的全部内容。
 (3)Range: bytes=-100           表示请求服务器只返回最后100个字节的内容。
 这个头字段,对于较大文档的断点续传非常有用,如果客户端在一次的请求中只接收到了服务器返回的部分内容就中断了,
 那么它可以在第二次的请求中使用Range头字段要求服务器只返回从上次中断位置以后的内容。这样就节省了网络下载的时间。
Content-Range: (响应消息头)用于指定服务器返回的部分实体内容的位置信息,例如:Content-Range: bytes 2543-4532/7898(起始位置-终止位置/整个实体内容的大小)。

 

一个使用GET方式的请求消息中不能包含实体内容,只有使用POST等方式的请求消息中才可以包含实体内容。

如果一个HTTP消息中包含了实体内容,那么在它的消息头部分必须要有Content-Length这个字段,用来告诉接收方实体内容的长度。

使用telnet来访问网络资源,体会HTTP协议的会话过程:
使用  telnet www.it315.org 80   连接上web服务器
然后输入  GET /index.html HTTP/1.1
          Host:

然后我们可以继续访问此服务器上的资源,如:
          GET /images/logo.gif HTTP/1.1
          Host: 
   Connection: close        ------表示访问完后断开连接。

 


URL类,URLConnection类,HttpURLConnection类。

工厂设计模式(XxxFactory-----getXxx())

 

一个获取网络资源的例子:

package com.heima.exam;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class GetWeb {
 
 public static void getContent(String urlString, String language) throws Exception {
  
  URL url = new URL(urlString);
  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  connection.setRequestProperty("Accept-Language", language);
  
  Map<String, List<String>> requests = connection.getRequestProperties();
  Set<String> reqFields = requests.keySet();
  for(Iterator itereq = reqFields.iterator(); itereq.hasNext(); ) {
   String field = (String) itereq.next();
   System.out.println(field + ":" + connection.getRequestProperty(field));
  }
  
  /*
   * 这个方法我们可以不调用,因为我们下面调用了getXxxxx()方法
   * 的时候就会自动跟服务器建立连接。
   * */
  //connection.connect();
  
  
  Map<String, List<String>> responses = connection.getHeaderFields();
  Set<String> resFields = responses.keySet();
  for(Iterator iteres = resFields.iterator(); iteres.hasNext(); ) {
   String field = (String) iteres.next();
   System.out.println(field + ":" + connection.getHeaderField(field));
  }
  
  BufferedReader bfr = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  String strLine = null;
  while((strLine = bfr.readLine()) != null) {
   System.out.println(strLine);
  }
  
  bfr.close();
  connection.disconnect();
 }

 /**
  * @param args
  */
 public static void main(String[] args) throws Exception {
  // TODO Auto-generated method stub

  getContent("http://www.baidu.com", "zh-HK");
  getContent("http://www.baidu.com", "ar-BH");
 }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值