第一章 网络编程入门
1.1 OSI参考模型
1. 物理层
传输介质,如双绞线和同轴电缆。
2. 数据链路层
负责在两个相邻节点无差错传输以帧为单位的数据。该层负责建立、维持和释放数据链路的连接,如交换机。
3. 网络层
该层负责选择合适的网间路由和交换节点。如路由器。
4. 传输层
该层任务是根据根据通信子网的特性最佳的利用网络资源,为两个端到端的会话层提供建立、维护和取消传输连接的功能。
5. 会话层
管理进程之间的会话过程。
6. 表示层
对上层数据进行转换。
7. 应用层
确定进程间通信的实际用途。
1.2 TCP/IP参考模型
TCP:传输控制协议,是一种面向连接的、可靠的协议。
UDP:不可靠的、无连接协议。
1. 应用层
基于TCP的应用层协议有以下几种:
FTP:文件传输协议
TELNET: 虚拟终端协议,允许从主机A登入到远程主机B,使得A充当B的虚拟终端。
HTTP:超文本传输协议
HTTPS:安全超文本传输协议
POP3:邮局协议-版本3
IMAP4:Internet消息访问协议-版本4,允许用户通过浏览器和操纵远程服务器上的邮件和邮件夹。
基于UDP的应用层协议有以下:
SNMP:简单网络管理协议
DNS:域名系统协议
2. 传输层
3. 网络互联层
4. 主机-网络层
1.3 IP协议
IP地址由两部分组成:IP网址和IP主机地址。
IP主机地址表示网络中的主机的地址。网络掩码用来确定IP地址中哪部分是网址,哪部分是主机地址。
比如IP:192.166.3.4 掩码:255.255.255.0
掩码对应的二进制:11111111.11111111.11111111.00000000
掩码与IP地址进行二进制与操作得到的便是IP地址
1.子网划分
如果网址为:192.166.0.0,则可以有2^16-2(65534)个主机,可以分出三个子网:192.166.1.0 192.166.2.0 192.166.3.0 这三个子网的掩码都是255.255.255.0
注:192.166.0.0为网络地址,192.166.111.111是广播地址,不能作为主机地址。
2.发送数据包的过程
IP是面向包的协议,数据被分成多个数据包,分别传输。IP网络上的主机只能向本地网上的其他主机发送数据包。
主机有两个不同性质的地址:物理地址和IP地址。物理地址由主机的网卡标识。物理地址才是主机的真实地址。
主机A向同一个网络上的主机B发包时,会通过地址解析协议(ARP)获得对方的物理地址,然后把包发给对方。
个人理解:以一台本地路由器为例,主机A发送包给主机B时,如果访问地址不是局域网内地址,则通过默认路由经过wan口转发出去,经过运营商的路由继续搜索。
3.域名
域名最右边的部分为顶层域名,最左边的为机器名称。
一般形式为:主机机器名.单位名.网络名.顶层域名
4.URL(统一资源定位器)
如:http://www.javathinker.org/bbs/index.jsp
“http”指超文本传输协议,“www.javathinker.org”是服务器的域名,“bbs”是网页所在路径,“index.jsp”是对应得网页文件。
1.4 TCP协议与端口
TCP协议使两台主机的进程顺利通信,不必担心丢包或包顺序混乱。TCP跟踪包顺序,但包顺序搞乱时按正确顺序重组包。如果包丢失,则TCP会请求源主机重发包。
IP协议根据主机的IP地址将数据发送到对应主机。TCP采用端口来区分进程。端口不是物理设备,而是逻辑地址。
端口号的范围是0-65535。0-1023的端口号一般固定分配给一些服务。例如21分配给FTP,25分配给SMTP,80分配给HTTP。
注意:在一个主机中TCP和UDP的端口取值范围是各自独立的,允许存在相同的TCP端口和UDP端口。
1.5 RFC简介
TCP/IP协议是以RFC文档形式发布的。RFC是描述互联网相关技术规范的文档。
1.6 Java编写C/S程序
本文Java程序都建立在TCP/IP协议基础上,致力于实现应用层。传输层向应用层提供了套接字Socket接口。它封装了下层的数据传输细节,应用层的程序通过Socket来建立与远程主机的连接和数据传输。
Java中有三种套接字类:java.net,Socket,java.net.ServerSocket,java.net.DatagramSocket。
前两种建立在TCP协议上,后一个建立在UDP协议上。
1.创建EchoServer
//将当前进程注册为服务器进程
ServerSocket server = new ServerSocket(8000);//指定8000端口
//监听
Socket socket = server.accept()//等待用户连接请求
Socket类提供getInputStream()方法和getOutputStream()方法返回输入和输出流对象。
代码如下:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 10 public class EchoServer { 11 private int port=8000; 12 private ServerSocket serverSocket; 13 14 public EchoServer() throws IOException{ 15 serverSocket = new ServerSocket(port); 16 System.out.println("服务器启动"); 17 } 18 19 public String echo(String msg){ 20 return "echo:"+msg; 21 } 22 23 private PrintWriter getWriter(Socket socket) throws IOException{ 24 OutputStream socketOut = socket.getOutputStream(); 25 return new PrintWriter(socketOut,true);//设为true,表示自动刷新 26 } 27 28 private BufferedReader getReader(Socket socket) throws IOException{ 29 InputStream socketIn = socket.getInputStream(); 30 return new BufferedReader(new InputStreamReader(socketIn)); 31 } 32 33 public void service(){ 34 while(true){ 35 Socket socket=null; 36 try{ 37 socket=serverSocket.accept(); 38 //socket.getPort()返回的是客户端套接字占用的本地端口 39 System.out.println("New connetion accepted "+socket.getInetAddress()+":"+socket.getPort()); 40 BufferedReader br = getReader(socket); 41 PrintWriter pw = getWriter(socket); 42 43 String msg =null; 44 while((msg=br.readLine())!=null){ 45 System.out.println(msg); 46 pw.println(echo(msg)); 47 if(msg.equals("bye")){ 48 break; 49 } 50 } 51 }catch(IOException e){ 52 e.printStackTrace(); 53 }finally{ 54 try{ 55 if(socket!=null) socket.close(); 56 }catch(IOException e){ 57 e.printStackTrace(); 58 } 59 } 60 } 61 62 } 63 public static void main(String args[])throws IOException{ 64 new EchoServer().service(); 65 } 66 }
2.创建EchoClient
String host="localhost";
String port="8000";
Socket socket=new Socket(host,port);
host表示EchoServer进程所在的主机的名字,port表示EchoServer进程监听的端口号。
代码如下:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.net.UnknownHostException; 9 10 public class EchoClient{ 11 private String host="localhost"; 12 private int port=8000; 13 private Socket socket; 14 15 public EchoClient() throws UnknownHostException, IOException{ 16 socket = new Socket(host,port); 17 18 } 19 20 private PrintWriter getWriter(Socket socket) throws IOException{ 21 OutputStream socketOut = socket.getOutputStream(); 22 return new PrintWriter(socketOut,true);//设为true,表示自动刷新 23 } 24 25 private BufferedReader getReader(Socket socket) throws IOException{ 26 InputStream socketIn = socket.getInputStream(); 27 return new BufferedReader(new InputStreamReader(socketIn)); 28 } 29 30 public void talk(){ 31 try{ 32 BufferedReader br =getReader(socket); 33 PrintWriter pw =getWriter(socket); 34 BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in)); 35 String msg=null; 36 while((msg=localReader.readLine())!=null){ 37 pw.println(msg); 38 System.out.println(br.readLine()); 39 if(msg.equals("bye")){ 40 break; 41 } 42 43 } 44 }catch(IOException e){ 45 e.printStackTrace(); 46 }finally{ 47 try{ 48 socket.close(); 49 }catch(IOException e){ 50 e.printStackTrace(); 51 } 52 } 53 } 54 55 public static void main(String[] args) throws UnknownHostException, IOException { 56 new EchoClient().talk(); 57 58 } 59 60 }