网络编程三要素
1、IP地址
要让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,在TCP/IP协议中,这个标识号就是IP地址。
Java提供了InetAddress类来获取和操作IP地址。
网络中计算机的唯一标识。
计算机只能识别二进制的数据,所以IP地址应该是一个二进制数据。我们配置的IP地址不是二进制的,为了方便表示IP地址,把IP地址的每一个字节上的二进制转换为十进制,术语“点分十进制”。
IP地址的组成:网络号段 + 主机号段
IP地址的分类:
A:第一号段为网络号段 + 后三段的主机号段
一个网络号: 256 * 256 * 256
B: 前二号段为网络号段 + 后二段的主机号段
一个网络号: 256 * 256
C: 前三号段为网络号段 + 后一段的主机号段
一个网络号: 256
192.168.x.x是私有地址
DOS:
ipconfig 查看本机ip地址
ping 后面跟ip地址,测试本机与指定ip地址间的通信是否正常。
特殊IP:127.0.0.1(表示本机)
x.x.x.255 广播地址,不建议使用
x.x.x.0 网络地址,不建议使用
import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressDemo { public static void main(String[] args) throws UnknownHostException { //static InetAddress getByName(String host) 在给定主机名的情况下确定主机的 IP 地址。 根据主机名和IP地址的字符串表示得到IP地址对象。 //InetAddress ia = InetAddress.getByName("MAYBE"); //传入IP地址或主机名都可以 InetAddress ia = InetAddress.getByName("192.168.181.1"); // String getHostName() 获取此 IP 地址的主机名。 主机名 String name = ia.getHostName(); // String getHostAddress()返回 IP 地址字符串(以文本表现形式)。 IP地址 String address = ia.getHostAddress(); System.out.println("name: " + name); System.out.println("address: " + address); } }
2、端口
物理端口网卡口
逻辑端口 我们指的是逻辑端口
A: 每个网络程序都会至少有一个逻辑端口
B:用于标识进程的逻辑地址,不同进程的标识
C:有效端口:0——65535,其中0——1024系统使用或保留端口。
3、协议
通信规则
UDP
将数据源和目的地封装成数据包中,不需要建立连接,每个数据包的大小限制在64k;因无连接,是不可靠协议;不需要建立连接,不可靠。
TCP
建立连接,形成传输数据的通道;在连接中进行大数据量传输了通过三次握手完成连接,是可靠协议,必须建立连接,效率低。
Socket套接字
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
原理机制:
1、通信的两端都有Socket;
2、网络通信其实就是Socket间的通信;
3、数据在两个Socket间通过IO传输。
UDP接收发送
//接收端 import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; /* * 接收UDP,接收端要先运行 * 类 DatagramSocket void receive(DatagramPacket p) 从此套接字接收数据报包。 * 类 DatagramPacket * A:创建Socket对象 DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口。 * B:创建一个数据包(接收容器) DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。 * C:调用Scoket对象接收数据 * D:解析数据包 byte[] getData() 返回数据缓冲区 * int getLength() 返回将要发送或接收到的数据的长度。获取实际长度 * E:释放资源 * */ public class UDPSocket2 { public static void main(String[] args) throws IOException { // DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的本地地址。 //创建接收端对象,本机只需指定端口号。 DatagramSocket ds = new DatagramSocket(10086); //每次要读的数据包 byte[] b = new byte[1024]; int length = b.length; //创建接收数据包 //DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。 DatagramPacket dp = new DatagramPacket(b, length); //接收数据 ds.receive(dp); //解析接收到的数据包
//String s = new String(dp.getData(), 0, dp.getData().length); byte[] ReceiveB = dp.getData(); int len = ReceiveB.length; String s = new String(ReceiveB, 0, len); //System.out.println(s); ds.close(); } } //---------------------------------------------------- //发送端 import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /* * UDP协议发送协议 * 1、首先创建发送端对象 * 2、创建数据并把数据打包 * 3、调用Socket发送方法发送数据包 * 4、释放资源 * * */ public class UDPSocket1 { public static void main(String[] args) throws IOException { //创建对象,UDP使用DatagramSocket这个类 DatagramSocket ds = new DatagramSocket(); //创建数据并打包,长度为 length 的包发送到指定主机上的指定端口号。 //设置IP地址 InetAddress ia = InetAddress.getByName("192.168.181.1"); //要发送的数据 byte[] b = "hello,UDP".getBytes(); int length = b.length; // DatagramPacket(byte[] buf, int length, InetAddress address, int port) 数据包、数据包大小、IP地址、端口号 DatagramPacket dp = new DatagramPacket(b, length, ia, 10086); //发送数据包 ds.send(dp); //发送数据包 void send(DatagramPacket p) 从此套接字发送数据报包。 //释放资源 ds.close(); } }
接收端相当于服务器,应该一直开着,不关闭。
多线程UDP
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class ReceiveThread implements Runnable { private DatagramSocket ds; public ReceiveThread(DatagramSocket ds) { this.ds = ds; } @Override public void run() { try { while (true) { // 创建一个包裹 byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据 ds.receive(dp); // 解析数据 String ip = dp.getAddress().getHostAddress(); String s = new String(dp.getData(), 0, dp.getLength()); System.out.println("from " + ip + " data is : " + s); } } catch (IOException e) { e.printStackTrace(); } } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class SendThread implements Runnable { private DatagramSocket ds; public SendThread(DatagramSocket ds) { this.ds = ds; } @Override public void run() { try { // 封装键盘录入数据 BufferedReader br = new BufferedReader(new InputStreamReader( System.in)); String line = null; while ((line = br.readLine()) != null) { if ("886".equals(line)) { break; } // 创建数据并打包 byte[] bys = line.getBytes(); // DatagramPacket dp = new DatagramPacket(bys, bys.length, // InetAddress.getByName("192.168.12.92"), 12345); DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.12.255"), 12306); // 发送数据 ds.send(dp); } // 释放资源 ds.close(); } catch (IOException e) { e.printStackTrace(); } } }
import java.io.IOException; import java.net.DatagramSocket; /* * 通过多线程改进刚才的聊天程序,这样我就可以实现在一个窗口发送和接收数据了 */ public class ChatRoom { public static void main(String[] args) throws IOException { DatagramSocket dsSend = new DatagramSocket(); DatagramSocket dsReceive = new DatagramSocket(12306); SendThread st = new SendThread(dsSend); ReceiveThread rt = new ReceiveThread(dsReceive); Thread t1 = new Thread(st); Thread t2 = new Thread(rt); t1.start(); t2.start(); } }
TCP发送数据的步骤: A:创建发送端Socket对象 类 Socket Socket(InetAddress address, int port)创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。 创建一个流套接字并将其连接到指定主机上的指定端口号。 这一步如果成功,就说明已经连接成功 B:获取输出流写数据 OutputStream getOutputStream() 返回此套接字的输出流。 C:释放资源 TCP协议一定要先开服务器,一定会保证数据被收到,所以接收端一定要被开启。 TCP接收: A:创建接收端Socket对象(服务器端的Socket对象ServerSocket) ServerSocket(int port) 创建绑定到特定端口的服务器套接字。 B:监听客户端连接,返回对应的Socket对象 Socket accept()侦听并接受到此套接字的连接。 C:获取输入流,读取数据 InputStream getInputStream() 返回此套接字的输入流。 返回此套接字的输入流。 D:释放资源