java网路编程学习之路(1)

来源:互联网 发布:ldc1314中文数据手册 编辑:程序博客网 时间:2024/05/21 19:27

第一章        java网络编程入门

要想学习网络编程,计算机网络知识是必不可少的,首先简单了解什么是计算机网络。

举个例子,张三和李四互相之间进行书信交流,他俩只需要去做写信和投递这些事情,而至于信是如何送到对方手上他们是不需要关心的,邮局会帮他们完成中间的传递过程。同样的,计算机网络就好比邮局,它会为我们完成中间的一系列数据传输功能。

我们进行网络编程就只需要做写信和投递这些事情,也就是写代码去描述信件内容以及使用操作系统提供的计算机网络方面的服务(主要是socket)。下面开始从最最基础学起。

1.1  进程之间的通信

简单了解一下进程,所谓的进程可以理解为运行中的程序。程序是静态的,而进程是动态的。

写一个不断读取用户输入的小程序EchoPlayer.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class EchoPlayer {public String echo(String msg){return "echo:"+msg;}public void talk() throws IOException{BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String msg = null;while((msg=br.readLine())!=null){System.out.println(echo(msg));if(msg.equals("bye")){//当你输入bye时,该运行中的该程序(进程)就停止运行break;}}}public static void main(String[] args) throws IOException {new EchoPlayer().talk();}}

当我们写完这个代码时,不运行它,我们称之为程序,一旦我们运行了它,我们就叫它进程。操作系统中一般执行了很多进程,它们往往提供着不同的服务,而上面的例子就提供了根据用户输入字符串,输出显示相同的字符串。

如果我们要进行的是网络之间的信息传递,光在本地进行输入输出功能显示是不够的。所以我们要做的就是从电脑A(客户端)输入msg,然后将msg发生到电脑B(服务器端),电脑B输出显示msg,并且回发一个msg给电脑A。要进行网络编程,还是先简单了解一下计算机网络的概念。


1.2 计算机网络的概念

所谓的计算机网络,是指把分布在不同地理区域的计算机用通信线路互连起来的一个具有强大功能的网络系统。通俗来说,计算机网络就是通过电缆,电话线或是无线通信设施等互连的计算机的集合。我们计算机老师用英文称之network of networks,网络的网络,把小网络再给它网起来形成一个大网络。

计算机网络核心的知识点主要是网络协议。关于协议这个知识点比较抽象,用一个例子来说明理解起来比较容易,中国人想和日本人沟通交流,中国人说中文,日本人说日语,怎么进行沟通呢?双方达成一个协议,咱俩都去学英语,用英语进行沟通交流就可以了。所以所谓的协议,我理解就是大家共同遵守的一种规章制度。

计算机网络为什么要有众多协议呢?百度百科给的网络协议定义:计算机网络中进行数据交换而建立的规则、标准或约定的集合。例如,网络中一个微机用户和一个大型主机的操作员进行通信,由于这两个数据终端所用字符集不同,因此操作员所输入的命令彼此不认识。为了能进行通信,规定每个终端都要将各自字符集中的字符先变换为标准字符集的字符后,才进入网络传送,到达目的终端之后,再变换为该终端字符集的字符。当然,对于不相容终端,除了需变换字符集字符外。其他特性,如显示格式、行长、行数、屏幕滚动方式等也需作相应的变换

不同地区拥有自己的网络环境,这其中存在着差异,他们要想进行互相访问得遵循TCP/IP协议,美国人用的是英语,他们本身网络环境都是英语,中国人要想用QQ发中文给在美国的朋友发过去还不乱码了啊?所以他们通过共同遵守TCP/IP协议(作为一个标准语言,进行语言转换)。

1.3 OSI参考模型

计算机网络产生之初,每个计算机厂商都有一套自己的网络体系结构,他们之间互不相容。为次,国际标准组织ISO建立了专门研究开放系统互连体系结构(open system interconnection,简称OSI)的分委员会,他们就提出了OSI参考模型,就是网络中所说的7层。

应用层  表示层  会话层     传输层   网络层      数据链路层    物理层

1).物理层(Physical Layer)                        传输单位:比特流(bit)

传输信息离不开物理介质,但是物理介质并不在OSI的7层之内,有人把它称为OSI的第零层。物理层的任务就是为上一层提供物理连接。在这一层,数据做为原始的比特流进行传输。典型的设备是Hub(集线器)。

2).数据链路层(Data Link Layer)              传输单位:帧(Frame)

数据链路层要负责建立、维持和释放数据链路的链接。在传送数据时,如果接收方检测到所传数据中有差错,就要通知发送方重发这一帧。典型的设备是Switch(交换机)。

3).网络层(Network Layer)                    传输单位:数据包(Datagram)

在两个计算机之间进行通信往往要经过多个数据链路,也可能还要经过多个通信子网。网络层的任务就是选择合适的网间路由和交换节点,确保数据能及时传送到目标主机。典型的设备是Router(路由器)。

4).传输层(Transport Layer)                  传输单位:报文(Segment)

该层的任务是根据通信子网的特性最佳地利用网络资源,为两个端系统(源主机和目标主机)的会话层提供建立、维护和取消传输连接的功能,以可靠方式或不可靠方式传输数据。所谓可靠方式就是确保数据能正确送达,而所谓不可靠方式就是不能确保数据能正确送达。

5).会话层(Session Layer)                      传输单位:报文

会话层管理进程之间的会话过程,即负责建立、管理、终止进程之间的会话。会话层还通过在数据中插入校验点来实现数据的同步。

6).表示层(Presentation Layer)                   传输单位:报文

表示层对上层数据进行转换,以保证一个主机的应用层的数据可以被另一个主机的应用层理解。表示层的数据转换包括对数据的加密、解密、压缩、解压和格式转换等。

7).应用层(Application Layer)                  传输单位:报文

应用层确定进程之间通信的实际用途,以满足用户实际需要。浏览网页,收发email,上传或下载文件等。


在上图中,AH/PH/SH/TH/NH和DH表示各个层加入的信息头,其中数据链路层还会为数据加上信息尾DT。

之所以加这么多头是因为在网络之间传递的数据过多,为了使数据能够正确的到达目的地会对其进行封装,就像信装进信封,信封上写上地址一样。

1.4 TCP、IP参考模型和TCP/IP协议

由于OSI模型过于复杂,难以完全实现于实际当中,所以我们一般用TCP/IP参考模型,TCP/IP参考模型吸取了网络分层的思想,而且对网络的层次进行了简化,并在网络各层(除了主机-网络层外)都提供了完善的协议,这些协议构成了TCP/IP协议集,简称TCP/IP协议。


1).主机-网络层

实际上TCP/IP参考模型没有真正提供这一层的实现,也没有提供协议。它只是要求第三方实现的主机-网络层能够为上层(网络互联层)提供一个访问接口,使得网络互联层能利用主机-网络层来传递IP数据包。

2).网络互联层

该层是整个参考模型的核心,它的功能是把IP数据包发送到目标主机。为了尽快的发送数据,它往往把数据分成多个数据包,然后发到目的地再根据各数据的头部信息进行数据重组。

3).传输层

使源主机和目标主机上的进程可以进行会话。在传输层定义了两种服务质量不同的协议,即TCP(transmission control protocol,传输控制协议)和UDP(user datagram protocol,用户数据报协议)。TCP协议是一种面向连接的可靠的协议,再进行数据传输前,需要通过三次握手进行连接。具体的三次握手可以通过wireshark抓包去深入了解。而UDP是一种不可靠、无连接的协议,主要使用于不需要对报文进行排序和流量控制的场合。UDP不能保证数据的接受顺序同发生顺序相同,甚至不能保证它们是否全部到达目标主机。应用层的一些协议,如SNMP和DNS协议,就建立在UDP协议的基础上。如果要去可靠的传输数据,则应该避免使用UDP协议,而使用TCP。

4).应用层

应用层引入了许多协议,基于TCP协议的应用层协议主要有以下几种。

● FTP (File Transfer Protocol) :文件传输协议,允许在网络上传输文件。

● TELNET:虚拟终端协议,允许从主机A登录到远程主机B,使得主机A充当主机B的虚拟终端。

● HTTP(Hyper Text Transfer Protocol):超文本传输协议,允许在网络上传送超文本。

● HTTPS(Secure Hyper Text Transfer Protocol):安全的超文本传输协议,对传输的数据是进行加密的。

● SMTP(simple mail transfer protocol):简单邮件传送协议,用于发送电子邮件。

基于UDP的应用层协议

● SNMP(simple network management protocol):简单的网络管理协议,为管理本地和远程的网络设备提供了一个标准化途径,是分布式环境中的集中化管理协议。

● DNS(Domian Name System):域名系统协议,把主机的域名转换成对应的IP地址。

1.4.1 IP协议

我们都知道每台主机都有唯一的IP地址,IP地址用于标识网络中的每个主机。IP地址是一个32为的二进制数序列。一般我们将其分为4个单元,每个单元占8位,然后用十进制表示每个单元。例如:192.166.2.3。现在全球主机数目太多,32位的IP地址表示的主机数目已经不能满足需求了,所以新的ipv6标准会取代上面的ipv4。

IP地址主要分为主机地址和网络地址。简单来说,网络地址就是区分你在哪个网段,主机地址就是区分你是这个网段中的哪一个主机。一般就是先找网段,再找主机。关于这一块我们只需要知道,子网掩码与上IP地址可以求得该IP地址所在的网段就行了。例如192.166.2.3这个IP地址的子网掩码是255.255.255.0,全部转换成二进制01代码再做与运算得网络地址为192.166.2.0。如果这个网段中有60台主机,那么IP地址范围就是192.166.2.1-192.166.2.60。一般0和255不用,因为有特殊用途。关于我们常说的域名主要是用来替代难记的IP地址的,你想浏览一个网页,你知道IP地址,但是你想记住很困难,而字符型的域名比长数字的IP地址要好记。关于域名是如何转换成IP地址就要用到DNS解析了。

1.4.2  TCP协议及端口

TCP协议使两台主机上的进程顺利通信,不必担心丢数据包等现象发生,因为丢了会重发。一般两个主机上的进程进行通信时,一开始通过IP协议根据主机B的IP地址将主机A上的进程A1发生的数据送达到主机B,而TCP负责将数据送到B上的进程B1。TCP采用的是端口号来区分进程。端口可以理解为标识进程的编号,客户进程的端口号一般是由操作系统动态分配的。此外我们主要注意的是,TCP和UDP端口的取值是各自独立的,就是进程A1是占用TCP端口1000,A2可以占用UDP端口1000,当然相同的协议就不可以了。


其实计算机网络方面的知识真的很重要,有时候电脑上不了网,配一下IP地址使其满足特定的网络,DNS设置8.8.8.8什么的。

我们知道IP地址不够用,像一个区域,例如学院内网络分配外网IP时都是应用DHCP协议进行分配的,内部区分用内网IP(随意分配,不重复就行),一旦该主机要访问外网时就给其分配一个外网IP,所以如果有些下载限制IP的,我们可以通过不停地要求重新分配外网IP进行限制的解除。

1.5   用java编写客户/服务器程序


进行网络编程,首先了解socket,什么是socket,socket就是操作系统为网络数据传输提供的接口,java对其又进行了封装,让我们使用起来更方便。

在java中,有3种套接字类:java.net.Socket, java.net.ServerSocket, java.net.DatagramSocket,其中前两个是建立在TCP协议基础上的,最后一个是建立在UDP基础上的。

下面主要以EchoServer和EchoClient为例,介绍如何用ServerSocket和Socket来编写服务器程序和客户程序。

1.5.1 创建EchoServer

服务器程序通过一直监听端口,来接受客户端程序的连接请求。

ServerSocket server = new ServerSocket(6666);//监听6666端口


ServerSocket的作用就是把当前进程注册为服务器进程。服务器程序接下来就可以调用server这个对象的accept()方法来接受客户端连接的请求,它会返回一个Socket对象。

Socket socket = server.accept();// 等待客户端连接请求


关于Socket类中很多具体方法我们可以查看API文档,我们主要用到的就是getInputStream()和getOutputStream()方法,一个读入数据,一个写出数据。服务器socket的getInputStream()对应客户端getOutputStream(),服务器端的getOutputStream()对应客户端getInputStream()。下面直接看具体实例吧。

服务器端代码EchoServer.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class EchoServer {private int port = 6666;private ServerSocket serverSocket;public EchoServer() throws IOException{serverSocket = new ServerSocket(port);System.out.println("服务器启动");}public String echo(String msg){return "echo:"+msg;}private PrintWriter getWriter(Socket socket) throws IOException{OutputStream socketOut = socket.getOutputStream();return new PrintWriter(socketOut,true);//true表示自动将中间缓存flush到接受数据端}private BufferedReader getReader(Socket socket) throws IOException{InputStream socketIn = socket.getInputStream();return new BufferedReader(new InputStreamReader(socketIn));}public void service(){while(true){Socket socket = null;try{socket = serverSocket.accept();System.out.println("新连接接入"+socket.getInetAddress()+":"+socket.getPort());BufferedReader br = getReader(socket);PrintWriter pw = getWriter(socket);String msg = null;while((msg=br.readLine())!=null){System.out.println("服务器端收到:"+msg);pw.println("服务器端发出:"+echo(msg));if("bye".equals(msg)){//如果客户端发送bye就结束通信break;}}}catch (Exception e) {e.printStackTrace();}finally{try{if(socket!=null){socket.close();//端口连接}}catch (Exception e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException {new EchoServer().service();}}


对于socket对象中获取的输入输出流,我们用PrintWriter装饰输出流,用BufferedReader装饰输入流,这样可以获得更多更好的方法。例如readLine()方法读取客户端发送的字符串。println()向客户端输出字符串。

1.5.2 创建EchoClient

在EchoClient程序中,为了与EchoServer通信,需要先创建一个Socket对象:

private String host="localhost";//因为用本地做测试所以写localhost,如果跟其他主机写服务器端IP地址或主机名private int port = 6666;private Socket socket;

参数host表示EchoServer所在的主机的名字,我们也可以写IP地址127.0.0.1表示本地。
以下是客户端代码EchoClient.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import java.net.Socket;public class EchoClient {private String host="localhost";//因为用本地做测试所以写localhost,如果跟其他主机写服务器端IP地址或主机名private int port = 8000;private Socket socket;public EchoClient() throws IOException{socket = new Socket(host,port);}private PrintWriter getWriter(Socket socket) throws IOException{OutputStream socketOut = socket.getOutputStream();return new PrintWriter(socketOut,true);//true表示自动将中间缓存flush到接受数据端}private BufferedReader getReader(Socket socket) throws IOException{InputStream socketIn = socket.getInputStream();return new BufferedReader(new InputStreamReader(socketIn));}public void talk(){try{BufferedReader br = getReader(socket);PrintWriter pw = getWriter(socket);BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));//输入流(从控制台输入)String msg = null;while((msg=localReader.readLine())!=null){//读入控制台输入到msgpw.println(msg);System.out.println(br.readLine());if("bye".equals(msg)){System.exit(0);}}}catch (Exception e) {e.printStackTrace();}finally{try{socket.close();}catch (Exception e) {e.printStackTrace();}}}public static void main(String[] args) throws IOException {new EchoClient().talk();}}


我们先运行EchoServer.java启动服务器,然后运行客户端程序EchoClient.java,从EchoClient的控制台输入一个数据可以在Server端显示出来,同时服务器端发送相同数据给Client,如果Client发送bye则Client和服务器断开连接,程序运行停止,而服务器则break出来内层的那个取出客户端发送数据while循环,外层有个while(true),所以它会等待下一个客户端的连接,并不会停止运行。





这篇博客写了很长时间,想写个网络编程专栏,希望能对大家有所帮助。由于知识面有限,可能有些地方不对或是写的不好,欢迎大家批评建议,大家共同学习。

0 0
原创粉丝点击