您的位置:首页 > 理论基础 > 计算机网络

黑马程序员--Java学习日记之网络编程

2015-06-27 12:17 585 查看


------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、网络编程概述

1、计算机网络

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的的管理和协调下,实现资源共享和信息传递的计算机系统。

2、什么是网络编程

网络编程就是用来实现网络互联的不同计算机上运行的程序间可以进行数据交换。

3、网络模型

①网络模型一般是指OSI参考模型、TCP/IP参考模型:

OSI参考模型分七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
TCP/IP参考模型分四层:应用层、传输层、网际层、主机至网络层。

②网络模型图如下图所示:



③网络模型的七层概述:

物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。

网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。

传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。

会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。

应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

4、网络通信三要素

①IP地址:InetAddress 网络中设备的标识,不易记忆,可用主机名。

在java中,为了方便我们的获取和操作,提供了一个InetAddress供我们使用。

InetAddress类的使用

在InetAddress类中,是没有构造方法的,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回本类对象。

InetAddress i = InetAddress.getLocalHost();

常用功能:

getByName:获取任意主机

getHostName:主机名

getHostAddress:主机Ip地址

InetAddress常用方法演示如下:

package com.huang.socket.p1;
02.
03.import java.net.InetAddress;
04.import java.net.UnknownHostException;
05.
06./**
07. *@author huangxiang
08. *@date 创建时间:2015年6月5日下午4:38:07
09. *@version 1.0
10. */
11.public class IPDemo {
12.
13.    public static void main(String[] args) throws UnknownHostException {
14.//      InetAddress ia = InetAddress.getByName("hx-pc");
15.//      System.out.println(ia.getHostAddress());
16.//      System.out.println(ia.getHostName());
17.//      System.out.println(ia);//hx-pc/115.150.230.25
18.//      InetAddress [] ia2 =InetAddress.getAllByName("hx-pc");
19.
20.        InetAddress ia = InetAddress.getLocalHost();
21.        System.out.println(ia.toString());//hx-pc/100.74.18.52
22.        System.out.println(ia.getHostAddress());//100.74.18.52
23.        System.out.println(ia.getHostName());//hx-pc
24.
25.        //也可以用数组的形式获取其ip
26.        byte[] i = ia.getAddress();
27.        for (int j = 0; j < i.length; j++) {
28.            if(!(j == i.length-1))
29.                System.out.print(i[j]+".");
30.            else {
31.                System.out.println(i[j]);//100.74.18.52
32.            }
33.        }
34.    /*常用方法
35.     *  byte[] getAddress()
36.                返回此 InetAddress 对象的原始 IP 地址。
37.        static InetAddress[] getAllByName(String host)
38.                在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
39.        static InetAddress getByAddress(byte[] addr)
40.                在给定原始 IP 地址的情况下,返回 InetAddress 对象。
41.        static InetAddress getByAddress(String host, byte[] addr)
42.                根据提供的主机名和 IP 地址创建 InetAddress。
43.        static InetAddress getByName(String host)
44.                在给定主机名的情况下确定主机的 IP 地址。
45.        String getCanonicalHostName()
46.                获取此 IP 地址的完全限定域名。
47.        String getHostAddress()
48.                返回 IP 地址字符串(以文本表现形式)。
49.        String getHostName()
50.                获取此 IP 地址的主机名。
51.        static InetAddress getLocalHost()
52.                返回本地主机。
53.
54.     */
55.    }
56.}


②端口号

a、物理端口,端口号指的是网卡口。

b、逻辑端口,我们指的就是逻辑端口。

A:每个网络程序都会至少有一个逻辑端口。

B:用于标识进程的逻辑地址,不同进程的标识。

C:有效端口:0~65535,其中0~1024系统使用或保留端口。

③传输协议:UDP和TCP

传输协议主要有两种,一种是UDP,一种是TCP

a、UDP:是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址。它在网络上以任何可能的路径传往目的地,因此能否到达目的地、到达目的地的时间、内容的准确性都是不能被保证的。

b、TCP:是一种面向连接的保证可靠传输的协议。通过TCP,得到的是一个顺序的无差错的数据流,发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常为sever socket)等待建立连接时,另一个socket可以要求进行连接,一旦两个连接建立,他们就可以进行双向的数据传输,双方都可以进行发送或者接收操作。

c、UDP和TCP的比较

UDP:1、每个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接。
2、UDP传输数据限制大小,每个数据包的大小在64KB之内。
3、因其无连接,是个不可靠的协议。发送方所发送的数据不一定以相同的次序到达接收方。
4、不需要建立连接,传输速度快。

TCP :1、面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接时间。
2、在连接中进行大量数据传输,但传输数据大小有限制,一旦双方的数据连接建立起来,双方的socket就可以按照统一的格式进行大数据传输。
3、通过三次握手完成连接,是可靠协议。
4、必须建立连接,效率相对较低。

d、TCP和UDP的应用:

TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

二、基于Socket的java网络编程

1、什么是Socket?

网络上的两个程序通过一个双向的通讯实现数据交换,这个双向链路的一端称为一个scoket。socket通常用来实现客户端和服务端的连接,socket是TCP/IP协议的一个十分流行的编程界面,一个socket由一个IP地址和一个端口号唯一确定。
但是,Socket所支持的协议并非TCP/IP一种,所以两者之间并没有什么必然的联系。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

2、Socket通信的过程

Sever端Listen某个端口是否有连接请求,Client端向Sever端发出Connect请求,Server端向Client端回Accept消息,一个连接就建立起来了。Server端和Client端都可以通过send、write等方法与对方通信。

对于一个功能齐全的Socket,都要包含以下结构:

a、创建Socket
b、打开连接到Socket的IO流
c、按照一定的协议对Socket进行读写操作
d、关闭socket

java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。

3、UDP传输

①建立UDP传输的步骤:

建立发送端和接收端(发送端和接收端是两个独立的运行程序)
建立数据包
调用Socket的发送和接收方法。
关闭Socket。

②方法:

DatagramSocket类表示用来发送和接收数据包的套接字,在DatagramSocket上总是启用UDP广播发送,为了接收端能够接收到广播包应该将DatagramSocket绑定到通配符地址上。

接收:void receive(DatagramPacket dp);

发送:void send(DatagramPacket dp);

DatagramPacket类表示数据包。用来实现无连接包投递服务。每条报文仅根据该包中包含的信息,从一台机器路由到另一台机器

③步骤:

a、发送端的建立:

建立UDPSocket服务,在此无需指定端口,也可以将端口加入。如果不指定的话,系统会随机分配一个端口,如第一次运行时端口为1093,那么第二次就会顺延为1094,再运行会一直顺延,因为之前的端口还没有得到释放,所以会顺延端口号值。
提供数据,并将数据封装到数据包中
通过socket服务的发送功能,将数据包发送出去
关闭资源

代码实现:

[java] view plaincopy
01.DatagramSocket socket = new DatagramSocket();
02.        byte[] byteArray = "你好".getBytes();
03.        InetAddress ip = InetAddress.getByName("Lenovo-PC");
04.        int port = 8888;
05.        DatagramPacket pak = new DatagramPacket(byteArray,
06.                            byteArray.length,
07.                            ip,
08.                            port);
09.        socket.send(pak);
10.        socket.close();

接收端的建立:

DatagramSocket socket = new DatagramSocket(8888);
02.        byte[] byteArray = new byte[1024];
03.        DatagramPacket pak = new DatagramPacket(byteArray,
04.                            byteArray.length);
05.        socket.receive(pak);
06.        byte[] byteArray2 = pak.getData();
07.        String info = new String(byteArray2,0,pak.getLength());
08.        System.out.println("接收到信息:" + info);
09.        socket.close();、


一个聊天小程序:
package com.huang.socket.chat;
02.
03.import java.io.BufferedReader;
04.import java.io.InputStreamReader;
05.import java.net.DatagramPacket;
06.import java.net.DatagramSocket;
07.import java.net.InetAddress;
08.
09./**
10. *@author huangxiang
11. *@date 创建时间:2015年5月5日下午8:35:33
12. *@version 1.0
13. */
14.//发送线程。
15.public class Send implements Runnable{
16.    //定义socket服务引用。
17.    public DatagramSocket ds;
18.    public Send(DatagramSocket ds){
19.        this.ds = ds;
20.    }
21.    @Override
22.    public void run() {
23.        try {
24.            //键盘录入数据
25.            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
26.            String line = null;
27.
28.            while((line = br.readLine())!=null){
29.                byte[] buf = line.getBytes();
30.
31.                DatagramPacket dp =
32.                        new DatagramPacket(buf,buf.length,InetAddress.getByName("hx-pc"),10006);
33.                //发送
34.                ds.send(dp);
35.
36.                if("886".equals(line))
37.                    break;
38.            }
39.            //关闭资源。
40.            ds.close();
41.        } catch (Exception e) {
42.            throw new RuntimeException("发送失败!");
43.        }
44.    }
45.}


package com.huang.socket.chat;
02.
03.import java.net.DatagramPacket;
04.import java.net.DatagramSocket;
05.
06./**
07. *@author huangxiang
08. *@date 创建时间:2015年5月5日下午8:35:43
09. *@version 1.0
10. */
11.//接收线程
12.public class Rece implements Runnable{
13.    //定义socket引用。
14.    public DatagramSocket ds;
15.
16.    public Rece(DatagramSocket ds){
17.
18.        this.ds = ds;
19.    }
20.    //复写run方法
21.    @Override
22.    public void run() {
23.        try {
24.            while(true){
25.            //定义数据包
26.            byte[] buf = new byte[1024];
27.
28.            DatagramPacket dp = new DatagramPacket(buf,buf.length);
29.            //接收数据包
30.            ds.receive(dp);
31.            //获取数据。
32.            String ip = dp.getAddress().getHostAddress();
33.            String data = new String(dp.getData(),0,dp.getLength());
34.
35.            if("886".equals(data)){
36.                System.out.println(ip+".......离开聊天室");
37.                break;
38.            }
39.            System.out.println(ip+":"+data);
40.        }
41.        }catch (Exception e) {
42.            throw new RuntimeException("接收失败");
43.        }
44.    }
45.
46.}


package com.huang.socket.chat;
02.
03.import java.net.DatagramSocket;
04./**
05. *@author huangxiang
06. *@date 创建时间:2015年5月5日下午8:38:09
07. *@version 1.0
08. */
09./*
10. * 需求:编写一个聊天程序
11. * 有收数据和发数据的部分。
12. * 这两部分需要同时执行。
13. * 这就需要用到多线程技术,一个线程控制收,一个线程控制发。
14. * 因为收和发的动作是不一致的,所以需要定义两个run()方法。将两个方法封装到不同的类中。
15. */
16.public class ChatDemo{
17.
18.    public static void main(String[] args) throws Exception{
19.        DatagramSocket sendSocket = new DatagramSocket();
20.        DatagramSocket receSocket = new DatagramSocket(10006);
21.
22.        new Thread(new Send(sendSocket)).start();
23.        new Thread(new Rece(receSocket)).start();
24.    }
25.
26.}


4、TCP传输

①TCP分客户端和服务端,客户端对应的对象是Socket,服务端对应的对象是ServerSocket。

客户端在Socket对象建立时就可以去连接指定主机,因为TCP是面向连接的,所以在建立Socket服务时就要有服务端存在并连接成功,形成通路后在该通道进行数据传输。

②实现步骤:

客户端:

a.创建Socket服务并指定要连接的主机和端口。

b.获取Socket流中的输出流(输入流)。

c.通过输出流将数据发送到服务端(或通过输入流读取服务端发送过来的数据)。

d.关闭客户端。

服务端:

a.建立服务端的Socket服务,通过new ServerSocket()并监听一个端口。

b.获取连接过来的客户端对象。通过ServerSocket对象的accept方法,该方法是阻塞式方法。

c.客户端如果发送过来数据,那么服务端要使用对应的客户端对象并获取到该客户端对象的读取流来读取发过来的数据并打印在控制台。

d.关闭服务端。(可选操作)

代码实现:

客户端:

package com.huang.socket.p2;
02.
03.import java.io.IOException;
04.import java.io.OutputStream;
05.import java.net.Socket;
06.import java.net.UnknownHostException;
07.
08./**
09. *@author huangxiang
10. *@date 创建时间:2015年5月5日下午7:21:16
11. *@version 1.0
12. */
13./*
14. * 演示tcp传输。
15.1、tcp分客户端和服务端。
16.2、客户端对应的对象是Socket。
17.      服务端对应的对象是ServerSocket。
18.*/
19./*
20. * 客户端,
21.通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。
22.因为tcp是面向连接的。所以在建立socket服务时,
23.就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
24.需求:给服务端发送给一个文本数据。
25.步骤:
26.1,创建Socket服务。并指定要连接的主机和端口。
27.*/
28.public class TcpClient {
29.
30.    public static void main(String[] args) throws UnknownHostException, IOException {
31.        //创建socket服务,并指定要连接的主机和端口
32.        Socket s = new Socket("hx-pc", 10000);
33.
34.        //为了获取数据,应获取socket中的输出流
35.        OutputStream out = s.getOutputStream();
36.
37.        out.write("哈哈哈,老子来了".getBytes());
38.
39.        s.close();
40.    }
41.
42.}

服务端:

package com.huang.socket.p2;
02.
03.import java.io.InputStream;
04.import java.net.ServerSocket;
05.import java.net.Socket;
06.
07./**
08. *@author huangxiang
09. *@date 创建时间:2015年5月5日下午7:21:32
10. *@version 1.0
11. */
12./*
13. * 需求:定义端点接收数据并打印在控制台上。
14.服务端:
15.1,建立服务端的socket服务。ServerSocket();
16.    并监听一个端口。
17.2,获取连接过来的客户端对象。
18.    通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
19.3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
20.    并打印在控制台。
21.4,关闭服务端。(可选)
22.*/
23.public class TcpSever {
24.
25.    public static void main(String[] args) throws Exception {
26.        //建立socket服务。
27.        ServerSocket ss = new ServerSocket(10000);
28.
29.        //获取连接过来的客户端对象
30.        while(true){
31.            Socket s = ss.accept();
32.            String ip = s.getInetAddress().getHostAddress();
33.            System.out.println(ip+".......connected");
34.        //获取客户端发来的数据,使用客户端对象的读取流来读取。
35.            InputStream in = s.getInputStream();
36.            byte[] buf = new byte[1024];
37.            int len = in.read(buf);
38.            System.out.println(new String(buf,0,len));
39.            s.close();
40.            ss.close();
41.        }
42.    }
43.
44.}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: