Java总结(11) 网络编程1

来源:互联网 发布:js appname 编辑:程序博客网 时间:2024/04/27 19:19


网络编程的一些概念

网络编程是什么?

网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外一个设备反馈的数据。现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序连接的程序被称作服务器(Server)。客户端程序可以在需要的时候启动,而服务器为了能够时刻相应连接,则需要一直启动。例如以打电话为例,首先拨号的人类似于客户端,接听电话的人必须保持电话畅通类似于服务器。连接一旦建立以后,就客户端和服务器端就可以进行数据传递了,而
且两者的身份是等价的。在一些程序中,程序既有客户端功能也有服务器端功能,最常见的软件就是BT、emule 这类软件了。下面来谈一下如何建立连接以及如何发送数据。

IP 地址和域名

在现实生活中,如果要打电话则需要知道对应人的电话号码,如果要寄信则需要知道收信人的地址。在网络中也是这样,需要知道一个设备的位置,则需要使用该设备的IP 地址,具体的连接过程由硬件实现,程序员不需要过多的关心。
IP 地址是一个规定,现在使用的是IPv4,既由4 个0-255 之间的数字组成,在计算机内部存储时只需要4 个字节即可。在计算机中,IP 地址是分配给网卡的,每个网卡有一个唯一的IP 地址,如果一个计算机有多个网卡,则该台计算机则拥有多个不同的IP 地址,在同一个网络内部,IP 地址不能相同。IP地址的概念类似于电话号码、身份证这样的概念。由于IP 地址不方便记忆,所以有专门创造了域名(Domain Name)的概念,其实就是给IP 取一个字符的名字,例如163.com、sina.com 等。IP 和域名之间存在一定的对应关系。如果把IP 地址类比成身份证号的话,那么域名就是你的姓名。其实在网络中只能使用IP 地址进行数据传输,所以在传输以前,需要把域名转换为IP,这个由称作DNS 的服务器专门来完成。所以在网络编程中,可以使用IP 或域名来标识网络上的一台设备。

端口的概念

为了在一台设备上可以运行多个程序,人为的设计了端口(Port)的概念,类似的例子是公司内部的分机号码。规定一个设备有216 个,也就是65536 个端口,每个端口对应一个唯
一的程序。每个网络程序,无论是客户端还是服务器端,都对应一个或多个特定的端口号。由于0-1024 之间多被操作系统占用,所以实际编程时一般采用1024以后的端口号。
使用端口号,可以找到一台设备上唯一的一个程序。所以如果需要和某台计算机建立连接的话,只需要知道IP 地址或域名即可,但是如果想和该台计算机上的某个程序交换数据的话,还必须知道该程序使用的端口号。

数据传输方式

知道了如何建立连接,下面就是如何传输数据了,先来看一下数据传输的方式。在网络上,不管是有线传输还是无线传输,数据传输的方式有两种:
TCP(Transfer ControlProtocol)
传输控制协议方式,该传输方式是一种稳定可靠的传送方式,类似于显示中的打电话。只需要建立一次连接,就可以多次传输数据。就像电话只需要拨一次号,就可以实现一直通话一样,如果你说的话不清楚,对方会要求你重复,保证传输的数据可靠。使用该种方式的优点是稳定可靠,缺点是建立连接和维持连接的代价高,传输速度不快。
UDP(User Datagram Protocol)
用户数据报协议方式,该传输方式不建立稳定的连接,类似于发短信息。每次发送数据都直接发送。发送多条短信,就需要多次输入对方的号码。该传输方式不可靠,数据有可能收不到,系统只保证尽力发送。

协议的概念

协议(Protocol)是网络编程中一个非常重要的概念,指的是传输数据的格式。因为大家在网络中需要传输各种各样的信息,在程序中获得到的都是一组数值,如何阅读这些数值呢,就需要提前规定好这组数据的格式,在客户端按照该格式生成发送数据,服务器端按照该格式阅读该数据,然后在按照一定的格式生成数据反馈给客户端,客户端再按照该格式阅读数据。现实中类似的例子就是电报编码,每个数字都是用特定的数据表达。一般程序的协议都分成客户端发送的数据格式,以及服务器端反馈的数据格式,客户端和服务器端都遵循该格式生成或处理数据,实现两者之间的复杂数据交换。

UDP网络编程

InetAddress 类 

java.net包中.
InetAddress类用于描述IP的类
没有构造方法.
使用静态方法来访问本类对象
常用方法:
   static | InetAddress getLocalHost() : 返回本地主机。
   static InetAddress getByName(String host) : 在给定主机名的情况下确定主机的 IP 地址。
   String getHostAddress() : 返回 IP 地址字符串(以文本表现形式)。
   String getHostName() : 获取此 IP 地址的主机名。 
示例:
获取百度IP
import java.net.InetAddress;  import java.net.UnknownHostException;    class IPDemo {      public static void main(String[] args) throws UnknownHostException {          InetAddress ia = InetAddress.getByName("www.baidu.com");          System.out.println(ia.getHostAddress());      }  }  

Socket

Socket就是为网络服务提供的一种机制。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。

DatagramSocket 类 

java.net 包中
构造方法: 
   DatagramSocket() 
                    构造数据报套接字并将其绑定到本地主机上任何可用的端口。
                     其他参与API.
常用方法:
   void send(DatagramPacket p) 
                     从此套接字发送数据报包

DatagramPacket 类

java.net 包中
构造方法:
   DatagramPacket(byte[] buf, int length) 
                      构造 DatagramPacket,用来接收长度为 length 的数据包。
   DatagramPacket(byte[] buf, int length, InetAddress address, int port)
                      构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 
                       其他参与API.
常用方法:
    int getPort() 
                     返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
    
    InetAddress getAddress() 
                      返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
     
    int getLength() 
                      返回将要发送或接收到的数据的长度。

UDP传输:

1:只要是网络传输,必须有socket 。
2:数据一定要封装到数据包中,数据包中包括目的地址、端口、数据等信息。
直接操作udp不可能,对于java语言应该将udp封装成对象,易于我们的使用,这个对象就是DatagramSocket. 封装了udp传输协议的socket对象。
因为数据包中包含的信息较多,为了操作这些信息方便,也一样会将其封装成对象。这个数据包对象就是:DatagramPacket.通过这个对象中的方法,就可以获取到数据包中的各种信息。
DatagramSocket具备发送和接受功能,在进行udp传输时,需要明确一个是发送端,一个是接收端。
udp的发送端:
1:建立udp的socket服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。
2:明确要发送的具体数据。
3:将数据封装成了数据包。
4:用socket服务的send方法将数据包发送出去。
5:关闭资源。

udp发送端

import java.net.*;class  UdpSend{        public static void main(String[] args)throws Exception {                // 1,建立udp的socket服务。                DatagramSocket ds = new DatagramSocket(8888);//指定发送端口,不指定系统会随机分配。                // 2,明确要发送的具体数据。                String text = "udp传输演示 哥们来了";                byte[] buf = text.getBytes();                // 3,将数据封装成了数据包。                DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("10.1.31.127"),10000);                // 4,用socket服务的send方法将数据包发送出去。                ds.send(dp);                // 5,关闭资源。                ds.close();        }}

udp的接收端:

1:创建udp的socket服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收端可以处理的数据。
2:定义数据包,用于存储接收到数据。
3:通过socket服务的接收方法将收到的数据存储到数据包中。
4:通过数据包的方法获取数据包中的具体数据内容,比如ip、端口、数据等等。
5:关闭资源。
class UdpRece {        public static void main(String[] args) throws Exception{                // 1,创建udp的socket服务。                DatagramSocket ds = new DatagramSocket(10000);                // 2,定义数据包,用于存储接收到数据。先定义字节数组,数据包会把数据存储到字节数组中。                byte[] buf = new byte[1024];                DatagramPacket dp = new DatagramPacket(buf,buf.length);                // 3,通过socket服务的接收方法将收到的数据存储到数据包中。                ds.receive(dp);//该方法是阻塞式方法。                // 4,通过数据包的方法获取数据包中的具体数据内容,比如ip,端口,数据等等。                String ip = dp.getAddress().getHostAddress();                int port = dp.getPort();                String text = new String(dp.getData(),0,dp.getLength());//将字节数组中的有效部分转成字符串。                System.out.println(ip+":"+port+"--"+text);                // 5,关闭资源。                ds.close();        }}

一个聊天程序

/* 编写一个聊天程序。 有收数据的部分,和发数据的部分。 这两部分需要同时执行。 那就需要用到多线程技术。 一个线程控制收,一个线程控制发。  因为收和发动作是不一致的,所以要定义两个run方法。 而且这两个方法要封装到不同的类中。   */  import java.net.*;  import java.io.*;    class Send implements Runnable// 发送端  {      private DatagramSocket ds;        public Send(DatagramSocket ds) {          this.ds = ds;      }        public void run()// 多线程覆盖run方法      {          try {              // 键盘录入              BufferedReader bufr = new BufferedReader(new InputStreamReader(                      System.in));                String len = null;                while ((len = bufr.readLine()) != null) {                  // 转换成字节数组发送数据                  byte[] buf = len.getBytes();                    DatagramPacket dp = new DatagramPacket(buf, buf.length,                          InetAddress.getByName("127.0.0.1"), 10001);                    ds.send(dp);                    if ("886".equals(len))                      break;              }          } catch (Exception e) {              throw new RuntimeException("发送端失败");          }      }  }    class Rece implements Runnable// 接收端  {      private DatagramSocket ds;        public Rece(DatagramSocket ds) {          this.ds = ds;      }        public void run() {          try {              while (true) {                  // 建立字节数组接收数据                  byte[] buf = new byte[1024];                    DatagramPacket dp = new DatagramPacket(buf, buf.length);                    ds.receive(dp);                    // 获取IP                  String ip = dp.getAddress().getHostAddress();                    // 将包转化成字符串                  String data = new String(dp.getData(), 0, dp.getLength());                    if ("886".equals(data)) {                      System.out.println(ip + "...离开聊天室");                      break;                  }                  // 打印                  System.out.println(ip + ".," + data);              }          } catch (Exception e) {              throw new RuntimeException("接收端失败");          }      }  }    class ChatDemo {      public static void main(String[] args) throws Exception {          // 创建接收端和发送端          DatagramSocket sendSocket = new DatagramSocket();          DatagramSocket receSocket = new DatagramSocket(10001);            // 开启多线程          new Thread(new Send(sendSocket)).start();          new Thread(new Rece(receSocket)).start();      }  }  



原创粉丝点击