网络编程定义:通过使用套接字来达到进程间通信编程
开发语言C、JAVA、VB等
网络编程的核心是IP、端口、协议三大元素
网络编程的本质是进程间通信
网络编程的2个主要问题:1是定位主机,2是数据传输
1. 七层网络模型
ISO(国际标准委员会组织)将数据的传递从逻辑上分为以下七层:
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
当发送数据时,需要按照上述七层进行一层一层加包的操作,再发出去。
当接收数据时,需要按照上述七层相反的次序一层层拆包,再解析出来。
2 IP地址
IP地址本质上是由32位二进制组成的整数,叫做ipv4,也有128位二进制组成的整数,叫做ipv6。
IP地址是设备在互联网中的唯一地址标识,通过该IP地址可以找到设备。
3 端口号
IP地址可以定位到具体某一台设备。
端口号可以定位到设备中具体某一个进程。
端口号本质就是由16位二进制组成的整数,范围是:0 ~ 65535,其中0 ~ 1024之间的端口号已经被系统占用,因此自己编程时从1025开始使用。
4 常见的网络协议
http - 超文本传输协议
ftp - 文件传输协议
tcp - 传输控制协议
udp - 用户数据报协议
ip - 互联网协议
... ...
协议 - 本质上就是一种约定/规则,用于描述不同主机之间通信的方式。
4.1基于tcp协议的编程模型
相关知识:
C/S - Client就是指客户端,Server就是指服务器。C/S架构
B/S - Browser就是指浏览器,Server就是指服务器。B/S架构
Socket - 本意为"插座",在网络编程中叫做用于通信的逻辑载体,该逻辑载体中包含了IP地址和端口号。
4.1.2 tcp编程模型
服务器:
(1)创建ServerSocket类型的对象,并提供端口号。
(2)等待客户端的连接请求,使用accept()方法。
(3)当客户端连接成功,则创建Socket对象使用输入输出流进行通信。
(4)关闭Socket对象和ServerSocket对象。
客户端:
(1)创建Socket类型的对象,并提供IP地址和端口号。
(2)使用输入输出流进行通信。
(3)关闭Socket对象。
3.3 相关类和方法的解析
(1)ServerSocket类
java.net.ServerSocket类是用于创建服务器套接字对象,用于等待客户端的连接。
ServerSocket(int port) - 创建于参数指定端口绑定的服务器套接字。
Socket accept() - 用于监听并接收客户端的连接请求。
void close() - 用于关闭服务器套接字。
(2)Socket类
java.net.Socket类是用于创建客户端套接字对象,套接字是两台主机通信的端点。
Socket(String host, int port) - 使用参数指定的IP地址和端口号进行对象的创建
InputStream getInputStream() - 用于获取当前套接字的输入流。
OutputStream getOutputStream() - 用于获取当前套接字的输出流。
void close() - 关闭套接字。
4.1.3基于udp协议的编程模型
编程模型
发送方:
(1)创建DatagramSocket类型的对象,不需要提供任何的信息。
(2)创建DatagramPacket类型的对象,指定发送的内容、IP地址以及端口号。
(3)发送数据,使用send()方法。
(4)关闭相关的资源。接收方:
(1)创建DatagramSocket类型的对象,并绑定指定的端口。
(2)创建DatagramPacket类型的对象,用于接收发来的数据。
(3)接收数据,使用receive()方法。
(4)关闭相关的资源。
2.2 相关类和方法的解析
(1)DatagramSocket类
DatagramSocket() - 使用无参的方式构造对象。
DatagramSocket(int port) - 使用参数指定的端口来创建对象并绑定。
void send(DatagramPacket p) - 发送参数指定的数据报。
void receive(DatagramPacket p) - 接收数据存放到参数指定的数据报。
void close() - 关闭套接字。
(2)DatagramPacket类
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
- 将参数指定的数据内容发送到参数指定的主机端口上。
DatagramPacket(byte[] buf, int length)
- 用于接收数据并存放到参数指定的位置上。
InetAddress getAddress() - 用于获取发送方/接收方的IP地址。
int getPort() - 用于获取发送方/接收方的端口号。
int getLength() - 用于获取发送方/接收方的数据长度。
(3)InetAddress类
static InetAddress getLocalHost() - 用于获取本机地址。
static InetAddress getByName(String host) - 根据主机名获取地址信息。
String getHostName() - 用于获取字符串形式的主机名。
String getHostAddress() - 用于返回字符串形式的IP地址。
tcp协议和udp协议的比较
1.1 tcp协议
tcp协议 - 传输控制协议,是一种面向连接的协议,类似打电话。
- 在通信的整个过程中全程保持连接
- 保证了数据传递的可靠性和有序性
- 是一种全双工的字节流通信方式
缺点 - 服务器压力比较大,资源消耗比较高,发送数据效率低
1.2 udp协议
udp协议 - 用户数据报协议,是一种非面向连接的协议,类似写信。
- 在通信的整个过程中不需要保持连接
- 是一种全双工的数据报通信方式
- 服务器压力比较小,资源比较低,发送数据效率比较高
缺点 - 不保证数据传递的可靠性和有序性
代码区
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Scanner;
public class TestStudents {
public static void main(String[] args) {
//提示用户输入信息并接收
System.out.println("请输入学号、姓名、密码 (以空格的方式分割)");
Scanner sc = new Scanner(System.in);
String str = sc.next();
//使用split进行分割,创建对象拆分学号、姓名、密码的信息。
String[] s =str.split(",");
Student sd = new Student();
sd.setId(Integer.parseInt(s[0]));
sd.setName(s[1]);
sd.setPssword(Integer.parseInt(s[2]));
//使用 OBJ关联写入到文本中,在读出来
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:/a.txt"));
oos.writeObject(sd);
System.out.println("写入成功!");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:/a.txt"));
try {
ois.readObject();
oos.close();
ois.close();
sc.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServerString {
public static void main(String[] args) {
try{
//1.创建ServerSocket类型的对象,并提供端口号
ServerSocket ss = new ServerSocket(8888);
//2.等待客户端的连接请求,使用accept()方法,保持阻塞状态
System.out.println("等待客户端的连接请求...");
Socket s = ss.accept();
System.out.println("客户端连接成功!");
//3.使用输入输出流进行通信
//服务器接收客户端发来的"hello"并打印
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String str = br.readLine();
System.out.println("str = " + str); // hello
//向客户端回发消息“I received!”
//4.关闭相关的套接字
br.close();
s.close();
ss.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
import java.io.DataOutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class TestClientString {
public static void main(String[] args) {
try{
//1.创建Socket类型的对象,并指定IP地址和端口号
Socket s = new Socket("192.168.99.234", 8888);
//2.使用输入输出流进行通信
//让客户端向服务器发送数据"hello"
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("hello");
System.out.println("成功发送数据到服务器!");
//等待接收服务器的回复,并打印回复的结果
//3.关闭Socket对象
ps.close();
s.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
import java.io.DataOutputStream;
import java.net.Socket;
public class TestClientData {
public static void main(String[] args) {
try{
//1.创建Socket类型的对象,并指定IP地址和端口号
Socket s = new Socket("192.168.99.234", 8888);
//2.使用输入输出流进行通信
//让客户端向服务器发送整型数据66
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeInt(66);
System.out.println("成功发送数据到服务器!");
//3.关闭Socket对象
s.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServerData {
public static void main(String[] args) {
try{
//1.创建ServerSocket类型的对象,并提供端口号
ServerSocket ss = new ServerSocket(8888);
//2.等待客户端的连接请求,使用accept()方法,保持阻塞状态
System.out.println("等待客户端的连接请求...");
Socket s = ss.accept();
System.out.println("客户端连接成功!");
//3.使用输入输出流进行通信
//服务器接收客户端发来的数据66并打印出来
DataInputStream dis = new DataInputStream(s.getInputStream());
int res = dis.readInt();
System.out.println("res = " + res); // 66
//4.关闭相关的套接字
s.close();
ss.close();
}catch(Exception e){
e.printStackTrace();
}
}
}