一、网络基础知识
- 每个网卡/机器都有一个或多个IP地址
- IPV4:192.168.0.100,每段从0到255
- IPV6:128bit长,分成8段,每段4个16进制数
FE80:0000:0000:0000:AAAA:0000:00C2:0002(其中连续的0000字段可以用::来代替) - 查看ip地址的命令
操作系统 | 命令 |
---|---|
Windows | ipconfig |
Linux/Mac | ifconfig |
- port:端口,0~65535,逻辑上的
端口号范围 | 说明 |
---|---|
0~1023 | OS已经占用了,80是Web,23是telnet |
1024-65535 | 一般程序可使用(谨防程序间端口冲突) |
- 两台机器的通讯就是基于IP+Port进行的,IP是计算机之间,Port保证了同一个程序之间
- 查询端口
操作系统 | 命令 |
---|---|
Windows/Linux/Mac | netstart-an |
- 保留ip:127.0.0.1本机地址
- 公网(万维网/互联网)和内网(局域网)
* 关于公网/内网的几点说明 |
---|
1. 公网是分层的 |
2. 最外层是公网/互联网 |
3. 底下的每层都是内网 |
4. ip地址可以在每个层次的网重用 |
5. traccert命令用于看当前机器和目标及其的访问中继(两者之间要经过多少交换机/网关) |
10. 通讯协议:TCP和UDP
通讯协议名称 | 特点 |
---|---|
TCP(Transmission Control Protocol) | - 传输控制协议,面向连接的协议 - 两台机器的可靠无差错的数据传输 - 双向字节流传递 |
UDP(User Datagram Protocol) | - 用户数据报协议,面向无连接 - 不保证可靠的数据传输 - 速度快,成本低,可以在较差网络下使用 |
二、UDP编程 (用户数据报协议)
计算机通讯:数据从一个IP的port出发(发送方),运输到另外一个IP的port(接收方)
UDP:无连接状态的通讯协议 |
---|
- 发送方发送消息,如果接收方刚好在目的地,则可以接受,如果不在,那这个消息就丢失了 |
- 发送方无法得知是否发送成功 |
- UDP的好处就是简单,节省,经济 |
类 | 方法和作用 |
---|---|
DatagramSocket:通讯的数据管道 | - send和receive方法 - (可选,多网卡)绑定一个IP和Port |
DatagramPacket | - 集装箱:封装数据 - 地址标签:目的地IP+Port |
实例:发送与接收数据 | -无主次之分 - 接收方必须早于发起方执行 |
实例:
- 接收数据
import java.net.*;
public class UdpRecv
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds=new DatagramSocket(3000);//DatagramSocket起到了接收方和发送方之间的数据管道的作用,端口为本机的3000
byte [] buf=new byte[1024]; //定义了一个字节数组
DatagramPacket dp=new DatagramPacket(buf,1024);//定义了一个集装箱
System.out.println("UdpRecv: 我在等待信息");
ds.receive(dp); //如果有数据进来,那么消息就被封装在dp里面,没有数据进来,那么就会一直卡在这里
System.out.println("UdpRecv: 我接收到信息");
String strRecv=new String(dp.getData(),0,dp.getLength()) +
" from " + dp.getAddress().getHostAddress()+":"+dp.getPort();
System.out.println(strRecv);
Thread.sleep(1000);
System.out.println("UdpRecv: 我要发送信息");
String str="hello world 222";
DatagramPacket dp2=new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("127.0.0.1"),dp.getPort());
ds.send(dp2);
System.out.println("UdpRecv: 我发送信息结束");
ds.close();
}
}
- 若只运行接收数据的类,则会输出以下结果:
UdpRecv: 我在等待信息
- 发送数据
import java.net.*;
public class UdpSend
{
public static void main(String [] args) throws Exception
{
DatagramSocket ds=new DatagramSocket();
String str="hello world";
DatagramPacket dp=new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("127.0.0.1"),3000);
System.out.println("UdpSend: 我要发送信息");
ds.send(dp);
System.out.println("UdpSend: 我发送信息结束");
Thread.sleep(1000);
byte [] buf=new byte[1024];
DatagramPacket dp2=new DatagramPacket(buf,1024);
System.out.println("UdpSend: 我在等待信息");
ds.receive(dp2);
System.out.println("UdpSend: 我接收到信息");
String str2=new String(dp2.getData(),0,dp2.getLength()) +
" from " + dp2.getAddress().getHostAddress()+":"+dp2.getPort();
System.out.println(str2);
ds.close();
}
}
- 若只运行发送数据的类,则会输出以下结果:
UdpSend: 我要发送信息
UdpSend: 我发送信息结束
UdpSend: 我在等待信息
- 若先运行其中任意一个类后再运行另一个类,则输出以下结果:(两个控制台打印信息不分先后)
UdpRecv: 我在等待信息
UdpRecv: 我接收到信息
hello world from 127.0.0.1:64766
UdpRecv: 我要发送信息
UdpRecv: 我发送信息结束
UdpSend: 我要发送信息
UdpSend: 我发送信息结束
UdpSend: 我在等待信息
UdpSend: 我接收到信息
hello world 222 from 127.0.0.1:3000
三、TCP:传输控制协议
TCP协议:有链接、保证可靠的无误差通讯
名称 | 步骤 |
---|---|
① 服务器 | 创建一个ServerSocket,等待连接 |
② 客户机 | 创建一个Socket,连接到服务器 |
③ 服务器 | ServerSocket接收到连接,创建一个Socket和客户的Socket建立专线连接,后续服务器和客户机的对话(这一对Socket)会在一个单独的线程(服务器端)上运行 |
④服务器 | ServerSocket继续等待连接,返回① |
* ServerSocket:服务器码头 |
---|
- 需要绑定port |
- 如果有多块2网卡,需要绑定一个IP地址 |
* Socket:运输通道 |
---|
- 客户端需要绑定服务器的地址和Port |
- 客户端往Socket输入流写入数据,送到服务端 |
- 客户端从Socket输入流读取服务器端过来的数据 |
- 服务端反之亦然 |
* 关于服务端与客户端的说明 |
---|
服务端等待响应时,处于阻塞状态 |
服务端可以同时响应多个客户端 |
服务端每接受一个客户端,就启动一个独立的线程与之对应 |
客户端或者服务端都可以选择关闭这对Socket的通道 |
* 实例 |
---|
1. 先启动服务端,且一直保留。只启动服务器端时发现控制台没有任何输出 |
2. 然后启动客户端。启动客户端后发现服务器端的控制台打印welcome to the java world |
3. 切换到客户端的控制台,输入Hello Server回车,控制台输出如下: |
![]() |
服务器端代码
import java.net.*;
import java.io.*;
public class TcpServer
{
public static void main(String [] args)
{
try
{
ServerSocket ss=new ServerSocket(8001); //驻守在8001端口
Socket s=ss.accept(); //阻塞,等到有客户端连接上来
System.out.println("welcome to the java world");
InputStream ips=s.getInputStream(); //有人连上来,打开输入流
OutputStream ops=s.getOutputStream(); //打开输出流
//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
ops.write(