zoukankan      html  css  js  c++  java
  • 网络编程

    一、网络编程基础

    java的网络通信可以使用TCP、IP和UDP等协议。在真正进行java网络编程之前,对这些协议进行简单的介绍。

    1、TCP协议

    TCP(Transmission Control Protocol),指的是传输控制协议,它是网络传输层的协议,主要负责数据的分组和重组。TCP协议提供了一种可靠的数据传输服务,它是面向连接的,大多数的网络应用程序都是用TCP协议来实现传输层。使用TCP协议创建一个网络应用程序非常容易,它可以保证数据传输的时间、顺序和内容正确无误。但是使用TCP 需要大量的网络开销,所以如果希望实现更高效的传输,使用TCP协议就不合适了。TCP所提供服务的主要特点如下:

    (1)面向连接的传输(可靠性的保证)

    (2)端到端的通信

    (3)高可靠性,确保传输数据的正确性,不出现丢失或乱序。

    (4)全双工方式传输

    (5)采用字节流方式,即以字节为单位传输字节序列(面向字节流)

    (6)紧急数据传送功能

    2、IP协议

    IP(Internet Protocol)(网络之间互联的协议)的缩写,中文简写成为“网协”,也就是为计算机网络互相连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。

    IP地址是一个32为(IPv4)或128(IPv6)的无符号数字,使用4组数字表示固定的编号,数字之间用一个点号隔开,例如“172.168.1.52”就代表网络中一个计算机唯一的地址编号。

    3、TCP/IP

    TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WAN)设计的。它是由ARPANET网的研究机构发展起来的。

    4、UDP协议

    UDP(User Datagram Protocol),指的是用户数据报协议。它和TCP协议一样,都是网络传输层上的协议,但是它与TCP有着本质的区别。使用UDP协议传输时,不保证数据一定能到达目的地,也不保证到达的顺序性。但是UDP协议占用的资源比较少,所以一般用在一些可靠性要求比较低的网络应用上,如网络视频会议、在线影视和聊天室等音频、视频数据传送。

    5、端口

    端口(Port)可以被理解为计算机与外界通信交流的窗户。当一个信息到达时,根据其请求的端口号不同,就可以知道应该提供哪个服务了

                                                                              常见服务端口表

    服务 端口
    HTTP 80
    FTP 21
    Telnet 23
    SMTP 25

    6、套接字

    套接字(Socket)是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端面点,简单说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。某个程序将一段信息写入套接字中,该套接字就会将这段信息发送给另一个套接字,就像电话线的两端一样,这样另一端的程序就通过另一个套接字收到这段信息。所以使用套接字编程有时也称为Socket编程

    7、java.net包

    在java的API中,java.net包是用来提供网络服务的,java.net包中含有各种专门用来开发网络应用程序的类,程序开发人员可以使用该包中的类很容易的建立基于TCP可靠连接的网络程序,以及基于UDP不可靠连接的网络程序。java.net包可以大致分为以下两个部分:

    (1)低级API,用于处理网络地址(也就是网络标识符,如IP地址)、套接字(也就是基本双向数据通信机制)和接口(用于描述网络接口)。

    (2)搞基API,用于处理URL(表示统一资源标识符)、URL(表示统一资源标识符)、URLConnection连接(表示到URL所指向资源的连接)等。

    二、InetAddress类

    任何一台运行在Internet上的主机都有IP地址和当地的DNS能够解析的域名。而在java.net包中相应的提供了IP地址的封装类InetAddress。

    InetAddress类用于描述和包装一个Internet IP地址,并提供了相关的常用方法,如解析IP地址的主机名称、获取本机IP地址的封闭、测试指定IP地址是否可达等。InetAddress实现java.io.Serializable接口,不允许继承。通过以下三种方法返回InetAddress实例。

        getLocalhost():返回封装本地地址的实例

       getAllByName(String host):返回封装Host地址的InetAddress实例数组

        getByName(String host):返回一个封装Host地址的实例。其中,Host可以是域名或者是一个合法的IP地址。

       InetAddress类的常用方法

     boolean      equals(Object obj)
              将此对象与指定对象比较。
     byte[] getAddress()
              返回此 InetAddress 对象的原始 IP 地址。
    static InetAddress[] getAllByName(String host)
              在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
    static InetAddress getByAddress(byte[] addr)
              在给定原始 IP 地址的情况下,返回 InetAddress 对象。
    static InetAddress getByAddress(String host, byte[] addr)
              根据提供的主机名和 IP 地址创建 InetAddress。
    static InetAddress getByName(String host)
              在给定主机名的情况下确定主机的 IP 地址。
     String getCanonicalHostName()
              获取此 IP 地址的完全限定域名。
     String getHostAddress()
              返回 IP 地址字符串(以文本表现形式)。
     String getHostName()
              获取此 IP 地址的主机名。
    static InetAddress getLocalHost()
              返回本地主机。
     int hashCode()
              返回此 IP 地址的哈希码。
     boolean isAnyLocalAddress()
              检查 InetAddress 是否是通配符地址的实用例行程序。
     boolean isLinkLocalAddress()
              检查 InetAddress 是否是链接本地地址的实用例行程序。
     boolean isLoopbackAddress()
              检查 InetAddress 是否是回送地址的实用例行程序。
     boolean isMCGlobal()
              检查多播地址是否具有全局域的实用例行程序。
     boolean isMCLinkLocal()
              检查多播地址是否具有链接范围的实用例行程序。
     boolean isMCNodeLocal()
              检查多播地址是否具有节点范围的实用例行程序。
     boolean isMCOrgLocal()
              检查多播地址是否具有组织范围的实用例行程序。
     boolean isMCSiteLocal()
              检查多播地址是否具有站点范围的实用例行程序。
     boolean isMulticastAddress()
              检查 InetAddress 是否是 IP 多播地址的实用例行程序。
     boolean isReachable(int timeout)
              测试是否可以达到该地址。
     boolean isReachable(NetworkInterface netif, int ttl, int timeout)
              测试是否可以达到该地址。
     boolean isSiteLocalAddress()
              检查 InetAddress 是否是站点本地地址的实用例行程序。
     String toString()
              将此 IP 地址转换为 String
     1 import java.io.IOException;
     2 import java.net.InetAddress;
     3 import java.net.UnknownHostException;
     4 
     5 public class javaTest2 extends Thread  {
     6 
     7     public static void main(String[] args) throws IOException {
     8         InetAddress ia=InetAddress.getLocalHost();
     9           System.out.println(ia);
    10         InetAddress ia1=InetAddress.getByName("www.baidu.com");
    11         System.out.println(ia1);
    12         System.out.println(ia.isReachable(1000));
    13     }  
    14 }

    运行结果: 1 qinghan/10.160.10.202 2 www.baidu.com/220.181.111.188 3 false 

    分析结果:当使用isReachable()函数时出现false的原因,查资料是因为防火墙阻止了外面进来的ICMP数据包

    注:查看api文档,发现InetAddress类没有构造函数~

    三、URL网络编程

    1、URL类

    URL由两部分组成:协议标识符和资源名称。其中“http”为使用的协议,它指的是超文本传输协议(HTTP)。其他常用的协议还包括文件传输协议(FTP)、Gopher、File和News。

    URL类提供了多个方法,可以获取URL对象协议、主机名、端口号、路径、查询字符串、文件名及资源引用。

    构造函数表

    URL(String spec)
              根据 String 表示形式创建 URL 对象。
    URL(String protocol, String host, int port, String file)
              根据指定 protocolhostport 号和 file 创建 URL 对象。
    URL(String protocol, String host, int port, String file, URLStreamHandler handler)
              根据指定的 protocolhostport 号、filehandler 创建 URL 对象。
    URL(String protocol, String host, String file)
              根据指定的 protocol 名称、host 名称和 file 名称创建 URL。
    URL(URL context, String spec)
              通过在指定的上下文中对给定的 spec 进行解析创建 URL。
    URL(URL context, String spec, URLStreamHandler handler)
              通过在指定的上下文中用指定的处理程序对给定的 spec 进行解析来创建 URL。

        URL的常用方法

    方法名称 方法说明
    getProtocol() 获得该URL的协议名
    getAuthority() 获得该URL的主机名和端口号
    getFile() 获得该URL的文件名
    getHost() 获得该URL的主机名
    getPath() 获得该URL的路径
    getPort() 获得该URL的端口号
    getQuery() 获得该URL 的查询字符串
    getRef() 获得该URL的引用锚记名

    代码:

     1 import java.net.MalformedURLException;
     2 import java.net.URL;
     3 
     4 public class javaTest2 extends Thread  {
     5 
     6     public static void main(String[] args) throws MalformedURLException  {
     7         URL url=new URL("http://www.baidu.com:80");//?后面表示参数,#后面表示锚点
     8         System.out.println("协议名:"+url.getProtocol());
     9         System.out.println("主机名和端口号:"+url.getAuthority());
    10         System.out.println("文件名:"+url.getFile());
    11         System.out.println("路径:"+url.getPath());
    12         System.out.println("查询字符串:"+url.getQuery());
    13         System.out.println("锚记名:"+url.getRef());
    14     }  
    15 }

    运行结果:

    1 协议名:http
    2 主机名和端口号:www.baidu.com:80
    3 文件名:
    4 路径:
    5 查询字符串:null
    6 锚记名:null
    "/index.html?username=tom#test"?后面表示参数,#后面表示锚点(相对路径)

    2、URLConnection类

    URLConnection类用来表示与URL建立的通信连接。位于java.net包中,调用URL类的openConnection()方法可以获得URLConnection对象。获得对象后,开发人员可以调用该对象的connect()方法来连接远程资源,代码如下。

     1 URL url=new URL("http://www.baidu.com"); 2 URLConnection urlc=url.openConnection(); 

    构造函数表

    protected URLConnection(URL url)
              构造一个到指定 URL 的 URL 连接。

    URL类和URLConnection类实现相同功能代码:

     1 import java.io.BufferedReader;
     2 import java.io.IOException;
     3 import java.io.InputStream;
     4 import java.io.InputStreamReader;
     5 import java.net.MalformedURLException;
     6 import java.net.URL;
     7 import java.net.URLConnection;
     8 
     9 public class javaTest2 extends Thread  {
    10 
    11     public static void main(String[] args) throws IOException  {
    12         URL url=new URL("http://www.baidu.com");
    13         InputStream is=url.openStream();
    14         //将字节流转换为字符流
    15         InputStreamReader isr=new InputStreamReader(is,"utf-8");
    16         //字符流输入添加缓冲
    17         BufferedReader bfr=new BufferedReader(isr);
    18         
    19         String data=new String(bfr.readLine().getBytes("utf-8"));
    20         System.out.println(data);
    21         
    22         
    23         URLConnection urlc=url.openConnection();
    24         InputStream is1=urlc.getInputStream();
    25         //将字节流转换为字符流
    26         InputStreamReader isr1=new InputStreamReader(is1,"utf-8");
    27         //字符流输入添加缓冲
    28         BufferedReader bfr1=new BufferedReader(isr1);
    29                 
    30         String data1=new String(bfr1.readLine().getBytes("utf-8"));
    31         System.out.println(data1);
    32         
    33         
    34         bfr.close();    bfr1.close();
    35         isr.close();    isr1.close();
    36         is.close();     is1.close();  
    37     }  
    38 }

    运行结果:

     1 � 2 � 

    打印的结果是一样的,但是出现的乱码问题没有解决(好烦啊~想了好久,用了挺多方法都不好使~)

    四、Scoket通信

    TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,基于TCP协议实现网络通信需要以下两种类协助实现:

    客户端:Socket类    服务器端:ServerSocket类

     

    注:建立连接的时候涉及到三次握手过程,释放连接时涉及到四次握手过程(TCP方式。。计算机网络知识)

     socket通信的实现步骤

    (1)创建serversocket和socket

    (2)打开连接到socket的输入输出流。

    (3)按照协议对socket进行读/写操作。

    (4)关闭输入输出流,关闭socket。

    1、基于TCP的socket通信

    服务器端

    1)创建serversocket对象,绑定监听端口号。

    2)通过accept()方法监听客户端请求

    3)连接建立后,通过输入输出流读取客户端发送的请求信息。

    4)通过输出流向客户端发送响应信息。

    5)关闭相关资源。

    客户端

    1)创建socket对象,指明需要建立连接的服务器地址和端口号。

    2)连接建立后,通过输出流向服务器端发送请求信息。

    3)通过输入流获取服务器响应的信息。

    4)关闭相应的资源。

     代码示例:

      1 /*
      2  * 服务器端(基于TCP的socket通信)
      3  */
      4 import java.io.BufferedReader;
      5 import java.io.BufferedWriter;
      6 import java.io.IOException;
      7 import java.io.InputStream;
      8 import java.io.InputStreamReader;
      9 import java.io.OutputStream;
     10 import java.io.OutputStreamWriter;
     11 import java.net.ServerSocket;
     12 import java.net.Socket;
     13 
     14 public class Server {
     15 
     16     public static void main(String[] args) {
     17         try {
     18             //创建一个服务器端的serversocket对象
     19             ServerSocket serverSocket=new ServerSocket(8888);
     20             //通过accept()方法监听客户端请求
     21             Socket socket=serverSocket.accept();
     22             //建立连接后,通过输入流获取客户端的请求信息
     23             InputStream is=socket.getInputStream();
     24             //将字节流信息转化为字符流
     25             InputStreamReader isr=new InputStreamReader(is);
     26             //创建输入流缓存
     27             BufferedReader br=new BufferedReader(isr);
     28             
     29             String data=br.readLine();
     30             System.out.println("客户端对服务器端说:我是"+data);
     31             
     32             //获取输出流,对请求作出相应的响应
     33             OutputStream os=socket.getOutputStream();
     34             //将字节流转化为字符流
     35             OutputStreamWriter osw=new OutputStreamWriter(os);
     36             //为输出流添加缓冲
     37             BufferedWriter bw=new BufferedWriter(osw);
     38             bw.write("hello "+data+"!");
     39             
     40             bw.flush();
     41             
     42             //关闭资源
     43             bw.close();
     44             osw.close();
     45             os.close();
     46             
     47             br.close();
     48             isr.close();
     49             is.close();
     50             socket.close();
     51             serverSocket.close();
     52            
     53         } catch (IOException e) {
     54             // TODO Auto-generated catch block
     55             System.out.println("连接建立失败");
     56             e.printStackTrace();
     57         }        
     58     }
     59 }
     60 
     61 
     62 /*
     63  *客户端(基于TCP的socket通信)
     64  */
     65 
     66 import java.io.BufferedReader;
     67 import java.io.BufferedWriter;
     68 import java.io.IOException;
     69 import java.io.InputStream;
     70 import java.io.InputStreamReader;
     71 import java.io.OutputStream;
     72 import java.io.OutputStreamWriter;
     73 import java.net.Socket;
     74 import java.net.UnknownHostException;
     75 import java.util.Scanner;
     76 
     77 public class Client {
     78 
     79     public static void main(String[] args) {
     80         //提示用户输入自己的姓名
     81     /*    String name=null;
     82         System.out.println("请输入你的姓名:");
     83         Scanner sc=new Scanner(System.in);
     84         name=sc.next();*/
     85         try {
     86             //创建客户端Socket,指定服务器地址和端口
     87             Socket socket=new Socket("localhost", 8888);
     88             //获取输出流,向服务器发送信息
     89             OutputStream os=socket.getOutputStream();
     90             //将字字节流转化成字符流
     91             OutputStreamWriter osw=new OutputStreamWriter(os);
     92             //创建字符流的缓冲
     93             BufferedWriter bw =new BufferedWriter(osw);
     94             
     95             osw.write("xiao");
     96             osw.flush();
     97             socket.shutdownOutput();//这句话作为客户端请求的结束标志,没有这就话客户端以为请求还没完事。
     98             
     99             //接收服务器端响应,并将响应结果打印
    100             InputStream is=socket.getInputStream();
    101             //将字节流信息转化为字符流
    102             InputStreamReader isr=new InputStreamReader(is);
    103             //创建输入流缓存
    104             BufferedReader br=new BufferedReader(isr);
    105             
    106             String data=br.readLine();
    107             System.out.println("服务器端对客户端说:"+data);
    108             
    109             //关闭资源
    110           //关闭资源
    111             bw.close();
    112             osw.close();
    113             os.close();
    114             
    115             br.close();
    116             isr.close();
    117             is.close();
    118             socket.close();
    119             
    120             
    121             
    122         } catch (UnknownHostException e) {
    123             // TODO Auto-generated catch block
    124             System.out.println("连接建立失败");
    125             e.printStackTrace();
    126         } catch (IOException e) {
    127             // TODO Auto-generated catch block
    128             System.out.println("连接建立失败");
    129             e.printStackTrace();
    130         }
    131     }
    132 }

    运行结果:服务器端输出

     1 客户端对服务器端说:我是xiao

    客户端输出

     1 服务器端对客户端说:hello xiao!  

    2、基于UDP的socket编程

    进行数据传输时,首先需要要将要传输的数据定义成数据报(Datagram)在数据报中指明数据所要达到的socket(主机地址和端口号),然后再将数据报发送出去。

    相关操作类:

    DatagramPacket:表示数据报包

    DatagramSocket:进行端到端的通信的类

    服务器端的实现步骤

    (1)创建DatagramSocket,指定端口号

    (2)创建DatagramPacket

    (3)接收客户端发送的数据信息

    (4)读取数据

    客户端实现步骤

    (1)定义发送的信息

    (2)创建DatagramPacket,包含将要发送的信息

    (3)创建DatagramSocket

    (4)发送数据

     代码示例:

     1 import java.io.IOException;
     2 import java.net.DatagramPacket;
     3 import java.net.DatagramSocket;
     4 import java.net.InetAddress;
     5 import java.net.SocketException;
     6 
     7 /*
     8  * 基于UDP的socket通信(服务器端)
     9  */
    10 public class Servier {
    11 
    12     public static void main(String[] args) throws IOException {
    13         /*
    14          * 接收客户端的请求信息
    15          */
    16         //创建服务器端的DatagramSocket,指定接口
    17         DatagramSocket datagramSocket=new DatagramSocket(8800);
    18         //创建服务器端DatagramPacket,用于接收客户端发送的数据报
    19         byte []data=new byte[1024];//创建字节数组,指定接收数据包的大小
    20         DatagramPacket datagramPacket=new DatagramPacket(data, data.length);
    21         //接收客户端发送的数据
    22         datagramSocket.receive(datagramPacket);
    23         //读取数据
    24         String info=new String(data,0,datagramPacket.getLength());
    25         System.out.println("我是服务器,客户端说:我是"+info);
    26         
    27         /*
    28          * 服务器端作出响应(向客户端发送数据)
    29          */
    30         //定义客户端的地址和端口号数据(可以从客户端发送过来的数据报对象获取)
    31         InetAddress address=datagramPacket.getAddress();
    32         int port=datagramPacket.getPort();
    33         
    34         byte[] data2=("欢迎你!"+info).getBytes();
    35         //创建数据报,包含响应的数据信息
    36         DatagramPacket datagramPacket2=new DatagramPacket(data2, 0, data2.length, address, port);
    37         //响应客户端,将信息传送给客户端
    38          datagramSocket.send(datagramPacket2);
    39        
    40          
    41         //关闭资源
    42          datagramSocket.close();
    43     }
    44 
    45 }
    46 
    47 import java.io.IOException;
    48 import java.net.DatagramPacket;
    49 import java.net.DatagramSocket;
    50 import java.net.InetAddress;
    51 import java.net.SocketException;
    52 import java.net.UnknownHostException;
    53 
    54 /*
    55  * 基于UDP的socket通信(客户端)
    56  */
    57 public class Client {
    58 
    59     public static void main(String[] args) throws IOException {
    60 
    61         /*
    62          * 发送客户端请求信息
    63          */
    64         //1、创建DatagramSocket对象 
    65         DatagramSocket datagramSocket =new DatagramSocket();
    66         //2定义服务器端的地址,端口号数据
    67         InetAddress address=InetAddress.getByName("localhost");
    68         int port=8800;//无法通过函数获取,只能自己赋值
    69         byte []data="小帅哥".getBytes();
    70         //3、创建DatagramPacket对象,用来发送客户端的请求信息的数据报
    71         DatagramPacket datagramPacket=new DatagramPacket(data, 0, data.length, address, port);
    72         //4.发送客户端的请求数据信息
    73         datagramSocket.send(datagramPacket);
    74         
    75         /*
    76          * 接收服务器端的响应信息
    77          */
    78         //创建接收数据包的字节数组
    79         byte []data1=new byte[1024];
    80          //创建DatagramPacket对象,用来接收服务器端的响应信息
    81         DatagramPacket datagramPacket1=new DatagramPacket(data1, data1.length);
    82         //接收服务器端的响应数据报信息
    83         datagramSocket.receive(datagramPacket1);
    84         //读取数据
    85         String info=new String(data1,0,datagramPacket1.getLength());
    86         System.out.println("我是客户端,服务器端说:"+info);
    87         
    88         //关闭资源
    89         datagramSocket.close();
    90 
    91     }
    92 
    93 }

    运行结果:服务器端输出:

     1 我是服务器,客户端说:我是小帅哥 

    客户端输出:

     1 我是客户端,服务器端说:欢迎你!小帅哥 

    3、Socket总结

    (1)对于同一个socket,如果关闭了输出流,则与该输出流关联的socket也会被关闭,所以一般不用关闭流,直接关闭socket流。(省事,但是每个资源都关是个好习惯~)

    (2)客户端与服务器端的通信,使用多线程,代码中可适当的降低线程的优先级,这样有利于提高运行速度。(网络编程不可避免要和多线程相关联)

    /*
    *实现多线程网络通信的思路
    */
    public class TcpRun extends Thread{
           
          public void run(){
            //to do something
          }
    
    }
     public static void main(String[] args) throws IOException {
    try{
    ServerSocket serverSocket
    =new ServerSocket(8888);
    //通过accept()方法监听客户端请求
    while(true){
    Socket socket
    =serverSocket.accept(); TcpRun tcpRun=new TcpRun();
    tcpRun.setPriority(4); //设置线程的优先级范围为[1,10],默认是5 tcpRun.start(); }catch(){
    //to do something
    }
    }

    (3)使用TCP通信传输一般为对象(使用ObjectOutputStream对象序列化,传递对象,或ObjectInputStream)

     下一篇就是重点用这个的一个小项目:http://www.cnblogs.com/xiaotiaosi/p/6389418.html

    (4)个人觉得,tcp和udp编程差别的原因:

    1)tcp是面向字节流的,udp面向数据报的

    2)tcp是面向连接的,udp不是面向连接的。

  • 相关阅读:
    字符,字节和编码
    Linux网络参数和ifconfig
    默认网关 网关 子网掩码 广播地址
    S.M.A.R.T.记录几块ssd硬盘
    linux 别名
    echo 输出颜色
    Linux:echo命令详解
    centos下安装mongodb 通过shell脚本
    linux查看登录用户
    linux wget指定下载目录和重命名
  • 原文地址:https://www.cnblogs.com/xiaotiaosi/p/6388684.html
Copyright © 2011-2022 走看看