网络编程总结-TCP/IP协议
TCP/IP协议
传输控制协议/因特网互联协议,又叫网络通讯协议。各个协议是Internet最基本的协议。
它定义了电子设备(如计算机)连入因特网的标准,以及数据如何在它们之间传输的标准。它既是互联网中的基本通信语言或协议,也是局域网的通信协议。
TCP/IP是一组包括TCP协议、IP协议、UDP协议、ICMP协议和其他一些协议的协议组。需要进行网络通信的计算机需要提供符合这些协议标准的程序以后,才能进行网络通信。
IP地址与端口号
ip协议简介
Internet Protocol简称IP,又译为网际协议或互联网协议
中文缩写为“网协”
为计算机网络相互连接进行通信而设计的协议
规定了计算机在因特网上进行通信时应当遵守的规则
任何厂家生产的计算机系统,只要遵守IP协议就可以与因特网互连互通。
是用在TCP/IP协议簇中的网络层协议
ip地址简介
互联网协议地址
IP地址是IP协议提供的一种统一的地址格式
它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
IP地址被用来给Internet上的电脑一个编号。
ip地址在本地局域网上是惟一的
每一个IP地址包括两部分:网络地址和主机地址
网络ID标识在同一个物理网络上的所有宿主机,主机ID标识该物理网络上的每一个宿主机
每个IP地址包括两个标识码(ID),即网络ID和主机ID。同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机ID与其对应。
物理地址:
又称为MAC地址
每个网卡在生产的时候,每个生产商都会给自己的网卡分配一个唯一的ID。
有些工具可以篡改掉。当然,如果局域网里面有两台MAC地址一样的机器,是会有问题的。
固定ip与动态ip
动态IP就是从DHCP服务器(路由器一般都有带,另外是一些系统上安装DHCP服务器)上动态分配一个IP,动态分配的这个IP根据DHCP服务器的设置不同,IP动态变化的时间也不同。
静态IP则是个人自己将IP手动绑定,IP的变化只能通过个人进行修改。
不同的网络设备一般会灵活使用两种方式,基本上在公司企业中都是两种模式共用
公网ip和私网ip
window上ipconfig查出来的是你本机的IP地址,也就是内网私有地址,此类地址仅在局域网使用,不能直接联通外网。
百度查出来的地址是你上网的共有地址,也许并不是你主机的地址,而是电信或联通分给你的地址,用于连接互联网。
出现这种规划的原因在于IPv4所能表示的IP太少而电脑太多以至于不够用,然而只有Public IP才能直接连接上网络,所以对于那些公司,学校,政府机构等场所,就可以集中使用私有的IP进行管理,而大家可以共用一个IP去连接上公网,这样,就省下了许多宝贵的Public IP
私网如常见的:172开头的和192开头的
当我们真正联网时,会先把数据发送到路由,然后再由路由进行处理实现真正的联网操作,路由的地址才是真正联网的Ip地址
A B C 类地址均为外网地址。为了便于内网访问,A B C类地址还留出了一部分私有地址作为内网地址供内网访问。具有内网ip的物理机可以通过NAT(网络地址转换)技术与外网通讯。
A类私有IP地址:
10.0.0.0~10.255.255.255
B类私有IP地址:
172.16.0.0~172.31.255.255
C类私有IP地址:
192.168.0.0~192.168.255.255
至于选择哪类私有地址,要根据内网的规模了。A B C 类内网规模依次减小。
有时看到b类的外网地址却使用的c类的私网,这个也是可以同过net技术实现的
169开头的是一个保留地址,是本地连接受限时系统自动分配的ip没有什么实际的意义,出现这种情况可能是服务器还没搭建好。
一个局域网内百度ip的地址是一样的
ip的唯一性
公网ip具有全球唯一性
ip地址分类
IPv4地址按照网络号和主机号的长度被分为五大类。A、B、C类用于为Internet(单播地址)中的设备接口分配地址,以及其他特殊情况下使用。类由地址中的头几位来定义:0为A类,10为B类,110为C类,1110为D类,1111为E类。D类地址供组播使用,E类地址保留。分类如下图所示:

由此可得出按此分类方式得到的IPv4地址空间划分:

这种IP地址结构分类的特点与缺陷是显而易见的,例如A类地址的网络数少但主机数多,C类地址的网络数多而主机数少,这往往会造成一个网络号内的主机号无法完全分配,造成IP地址资源的利用率低下的问题。从而使IPv4的地址资源很快就出现了枯竭的趋势,寻找进一步细分IP地址的方法也就成为了必然。
分类的目的:
A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验
子网寻址(细分主机号)
最初分类寻址的方法很难为接入Internet的新网段分配一个新的网络号,随着20世纪80年代初局域网(Local Area Network,LAN)的发展这一问题更为突出。为了解决这一问题,人们自然想到一种方式,在一个站点接入Internet后为其分配网络号,然后由站点管理员进一步划分本地的子网数。也即在初始的网络号+主机号的结构的基础上,将主机号划分为子网号+主机号,这样就可以在不改变核心路由基础的前提下细分网络。这种方法被称为子网寻址。
子网掩码
子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩
子网掩码将某个IP地址划分成网络地址和主机地址两部分。
使用的IPV6的话是没有子网掩码的概念,也没有网络号与主机号的概念
子网掩码是在IPv4地址资源紧缺的背景下为了解决lP地址分配而产生的虚拟lP技术,通过子网掩码将A、B、C三类地址划分为若干子网,从而显著提高了IP地址的分配效率,有效解决了IP地址资源紧张的局面。另一方面,在企业内网中为了更好地管理网络,网管人员也利用子网掩码的作用,人为地将一个较大的企业内部网络划分为更多个小规模的子网
子网掩码是一个32位的2进制数, 其对应网络地址的所有位都置为1,对应于主机地址的所有位都置为0。子网掩码告知路由器,地址的哪一部分是网络地址,哪一部分是主机地址
它的主要作用有两个,一是用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上。二是用于将一个大的IP网络划分为若干小的子网络。
对于A类地址来说,默认的子网掩码是255.0.0.0;对于B类地址来说默认的子网掩码是255.255.0.0;对于C类地址来说默认的子网掩码是255.255.255.0。
通过子网掩码,就可以判断两个IP在不在一个局域网内部。
网关
网关(Gateway)又称网间连接器、协议转换器。
网关在网络层以上实现网络互连
大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“关口”,这道关口就是网关。
说明:由于历史的原因,许多有关TCP/IP的文献曾经把网络层使用的路由器称为网关,在今天很多局域网采用都是路由来接入网络,因此通常指的网关就是路由器的IP
两个网络的通信过程
在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不同的网络里。
而要实现这两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机
网关ip地址
网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。
网关必须是电脑自己所在的网段中的IP地址,而不能填写其他网段中的IP地址。
127.0.0.1
本地回路地址:127.0.0.1(自己访问自己网卡用,别人无法用这个地址访问自己,别人用网卡对外提供的ip,有几个网卡就有几个ip)(ip是一个int型非负数组成,每个字节由.分割)
在命令行看ip,用命令ipconfig
ping
(Packet Internet Groper)因特网包探索器
Ping是工作在 TCP/IP网络体系结构中应用层的一个服务命令, 主要是向特定的目的主机发送 ICMP(Iternet Control Message Protocol 因特网报文控制协议)Echo 请求报文,测试目的站是否可达及了解其有关状态
看自己的计算机能否与另一台计算机连通,用ping ip地址
ping自己ip可以看网卡是否有问题
有效端口:0~65535(2^16-1,尽量使用1024以上的,1024以下是重要程序知名程序或服务占用)(一个端口运行一个程序)
1024 ~ 49151 提供一般应用程序使用.(Win Socket开发选中的范围)
动态或私有端口: 49151 (2^15+2^14-1)~ 65535
UDP与TCP(高级协议)
Udp:
(User Datagram Protocol)用户数据报协议,
- 面向无连接(发送数据无需建立连接)
- 不可靠(不能确保UDP数据报最终达到目的地, 对接收的数据不发送确认, 无法确定是否到达目的地, 数据不会重发)
- 不安全
- 字节开销小,速度快。
- 适合点对点传输(没有谁是服务器谁是客户端),并且安全性要求不高的网络应用程序。(如聊天)
Tcp:
(Transmission Control Protocol )传输控制协议
- 面向连接
- 提供可靠无差错的协议((当发送数据后, 要求对方返回一个确认信息, 如果没有接收到对方确认, 重发.))
- 基于字节流 (对发送的数据排序, 每个发送字节关联一个序列号. 对方根据此序列号进行数据排序, 确保数据的顺序).
- 安全
- 三次握手(连接请求,连接成功,发送数据)。
都是传输层的协议,
Socket说明
套接字(socket):应用程序可以通过它发送或接收数据,是IP地址与端口的组合。
Socket就是网络驱动层提供给应用程序编程的接口和一种机制。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
UDP传输
DatagramSocket与DatagramPacket
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法。
关闭Socket。
发送端与接收端是两个独立的运行程序。
发送端
在发送端,要在数据报对象中明确目的地IP及端口。
DatagramSocket ds = new DatagramSocket();
byte[] by = “hello,udp”.getBytes();
DatagramPacket dp = new DatagramPacket(by,0,by.length,
InetAddress.getByName(“127.0.0.1”),10000);
ds.send(dp);
ds.close();
接收端
在接收端,要指定监听的端口。
DatagramSocket ds = new DatagramSocket(10000);
byte[] by = new byte[1024];
DatagramPacket dp = new DatagramPacket(by,by.length);
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength());
System.out.println(str+"--"+dp.getAddress());
ds.close();
通过键盘录入获取要发送的信息。
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
br.readLine();
将发送和接收分别封装到两个线程中。
main()线程和new Thread()线程
实例:实现字符串的发送
这样运行两个程序
打印出:

TCP传输
TCP报文格式

上图中有几个字段需要重点介绍下:
(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
- FIN:释放一个连接。
需要注意的是:
(A)不要将确认序号Ack与标志位中的ACK搞混了。
(B)确认方Ack=发起方Req+1,两端配对。
步骤
Socket和ServerSocket
建立客户端和服务器端
建立连接后,通过Socket中的IO流进行数据的传输
关闭socket
同样,客户端与服务器端是两个独立的应用程序。
先运行服务器端再运行客户端
三次握手
TCP是面向连接的通信协议,通过三次握手建立连接
是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。
首先Client端发送连接请求报文(SYN报文)
server段接收连接后回复ACK报文,并为这次连接分配资源。
Client端接收到ACK报文后也向Server段发送ACK报文,并分配资源,这样TCP连接就建立了。
Ack报文:ACK (Acknowledge character)即是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。
为什么要client要再发送一次确认:
为了防止已经失效的客户端请求报文,再次传到服务端,因而产生错误。
四次挥手
指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开
1、先由客户端向服务器端发送一个FIN,请求关闭数据传输,客户端进入终止等待1状态2、当服务器接收到客户端的FIN时,向客户端发送一个ACK,服务器进入终止等待1状态,客户端收到服务器的确认请求后,此时,客户端就进入终止等待2状态,等待服务器发送连接释放报文
3、服务器向客户端发送一个FIN,告诉客户端应用程序关闭,服务器进入最后确认状态
当客户端收到服务器端的FIN是,回复一个ACK给服务器端,客户端进入时间等待状态
- 经过2MSL(最长报文段寿命)的时间后,进入CLOSED状态。服务器只要收到了客户端发出的确认,立即进入CLOSED状态。
服务器结束TCP连接的时间要比客户端早一些。
为什么客户端最后还要等待2MSL
TCP允许不同的实现可以设置不同的MSL值。
- 保证客户端发送的最后一个ACK报文能够到达服务器
- 防止“已经失效的连接请求报文段”出现在新的连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
为什么建立连接是三次握手,而关闭连接却是四次挥手
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP多线程
TCP网络程序的服务器端程序往往需要接受多个客户端的请求,如果总是单线程进行处理的话,很可能在请求较多的时候,有的请求无法得到及时的响应。要解决该问题,最好的办法就是采用多线程,用每一个线程处理一个请求。
客户端
客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream(),getOutputStream()获取即可。
与服务端通讯结束后,关闭Socket。
通过Socket建立对象并指定要连接的服务端主机以及端口。
Socket s = new Socket(“192.168.1.1”,9999);//给本机127.0.0.1
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes());
s.close();
代码:
查看代码
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class ReverseClient {
public static void main(String args[]) throws Exception {
Socket sock = new Socket("127.0.0.1", 6999);
//获得流
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
//接收欢迎语
Thread.sleep(10);
int len = in.available();
byte[] buf = new byte[len];
in.read(buf);
System.out.println(new String(buf));
//读键盘,发送数据
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
String line;
while(true) {
line = br.readLine();
out.write((line+"\r\n").getBytes());
if("quit".equals(line))
break;
Thread.sleep(10);
len = in.available();
buf = new byte[len];
in.read(buf);
System.out.println(new String(buf));
}
sock.close();
}
}
服务器端
服务端需要明确它要处理的数据是从哪个端口进入的。
用命令行中telnet命令可以tcp服务器,如telnet www.sina.com.cn 80。输入一个字符就向服务器发送一个字符,删除键也会算一个字符发送
当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。
当该客户端访问结束,关闭该客户端。
建立服务端需要监听一个端口
查看代码
ServerSocket ss = new ServerSocket(9999);//监听指定端口
Socket s = ss.accept ();//该方法将一直等待,直到客户端连接到服务器上给定的端口。
InputStream in = s.getInputStream();//通过Socket进行通信
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close();
代码:
查看代码
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ReverseServer {
/**
* 服务器程序,提供字符反向
*/
public static void main(String[] args) {
ServerSocket ss = null;
try {
//创建服务器,监听端口
ss = new ServerSocket(6999);
while(true) {
//等待用户的连接请求
Socket sock = ss.accept();
//开新线程,提供服务
new Thread(new ReverseServicer(sock)).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(ss!=null)
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}}}
和
查看代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class ReverseServicer implements Runnable {
private Socket sock;
public ReverseServicer(Socket sock) {
this.sock = sock;
}
public void run() {
try {
//获得流
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
// 发送欢迎语
out.write("欢迎光临本小站,提供字符反向的功能".getBytes());
//接收客户端发送的数据,反向,发送给客户端
BufferedReader br =
new BufferedReader(new InputStreamReader(in));
String line;
while(true) {
line = br.readLine();
if("quit".equals(line))
break;
System.out.println(line);
System.out.println(line.length());
//a b d backspace c c backspace d b a
StringBuilder sb = new StringBuilder(line);
sb.reverse();
System.out.println(sb);
out.write(sb.toString().getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}}}
实例:把服务器端的时间发送到客户端
不用打印流包装,用转换流包装也可以。
先运行服务器端,再运行客户端,会打印:

多线程实例
用TCP通信模型创建一个WEB服务器
IIS,Apache,Tomcat等WEB服务器基础原理都是采用Tcp通信模型的,只要上面代码ServerSocket监听的端口是80就可以通过在浏览器属于http://localhost/来访问该Socket,
即:ServerSocket ss = new ServerSocket(80);
在页面打印
TCP网络程序的工作原理
TCP客户端程序与TCP服务器端程序的交互过程:
服务器端程序创建一个ServerSocket,然后调用accept方法等待客户来连接。
客户端程序创建一个Socket并请求服务器端建立连接。
服务器端接收客户的连接请求,并创建一个新的Socket与该客户建立专线连接。
建立了连接的两个Socket在一个单独的线程(由服务器端程序创建)上对话。
服务器端开始等待i新的连接请求,当新的连接请求到达时,重复上述步过程。
跟Socket有关的流可通过关闭Socket来进行关闭

浙公网安备 33010602011771号