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()方法返回输入和输出流对象。
代码如下:
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=8000; 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,表示自动刷新 } 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(); //socket.getPort()返回的是客户端套接字占用的本地端口 System.out.println("New connetion accepted "+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(msg.equals("bye")){ break; } } }catch(IOException e){ e.printStackTrace(); }finally{ try{ if(socket!=null) socket.close(); }catch(IOException e){ e.printStackTrace(); } } } } public static void main(String args[])throws IOException{ new EchoServer().service(); } }
2.创建EchoClient
String host="localhost";
String port="8000";
Socket socket=new Socket(host,port);
host表示EchoServer进程所在的主机的名字,port表示EchoServer进程监听的端口号。
代码如下:
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; import java.net.UnknownHostException; public class EchoClient{ private String host="localhost"; private int port=8000; private Socket socket; public EchoClient() throws UnknownHostException, IOException{ socket = new Socket(host,port); } private PrintWriter getWriter(Socket socket) throws IOException{ OutputStream socketOut = socket.getOutputStream(); return new PrintWriter(socketOut,true);//设为true,表示自动刷新 } 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){ pw.println(msg); System.out.println(br.readLine()); if(msg.equals("bye")){ break; } } }catch(IOException e){ e.printStackTrace(); }finally{ try{ socket.close(); }catch(IOException e){ e.printStackTrace(); } } } public static void main(String[] args) throws UnknownHostException, IOException { new EchoClient().talk(); } }