Java学习笔记-Day38 Java 网络编程
一、TCP/IP协议栈
(1)TCP(传输控制协议):Transmission Control Protocol ,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
(2)UDP(用户数据报协议):User Datagram Protocol,用于处理数据包,是一种无连接的、不可靠的通信协议。
(3)IP(网络协议):Internet Protocol,把数据从源传送到目的地。它不负责保证传送可靠性,流控制,包顺序等。
(4)ICMP(网络控制报文协议):Internet Control Message Protocol,是TCP/IP协议栈的一个子协议,用于在IP主机、路由器之间传递控制消息。
(5)IGMP(网际组报文协议):Internet Group Management Protocol,是一个组播协议,运行在主机和组播路由器之间。
(6)ARP(地址解析协议):Address Resolution Protocol,根据IP地址获取物理地址的协议。
(7)HTTP(超文本传输协议):HyperText Transfer Protocol,是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。
(8)FTP(文件传输协议):File Transfer Protocol,用于Internet上的控制文件的双向传输。
二、IP地址与端口
1、IP地址
IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址。
IP地址类型分为公有地址和私有地址。
1.1、公有地址
公有地址(Public address)由因特网信息中心负责。这些IP地址分配给注册并向Inter NIC提出申请的组织机构。可以通过它直接访问因特网。
1.2、私有地址
私有地址(Private address)属于非注册地址,专门为组织机构内部使用。
以下列出留用的内部私有地址
A类 :10.0.0.0–10.255.255.255
B类 :172.16.0.0–172.31.255.255
C类 :192.168.0.0–192.168.255.255
2、端口
一台计算机上可以运行多个服务,服务用端口来区别。一台计算机上可以有65536个端口,每个端口对应一个唯一的程序。由于0-1024之间多被操作系统占用,所以实际编程时一般采用1024以后的端口号。
一些常见的服务对应的端口:
ftp:20/21、telnet:23、smtp:25、dns:53、http:80、https:443
三、Socket与ServerSocket
1、Socket类
Socket(套接字)就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
Socket 可以使一个应用从网络中读取和写入数据,不同计算机上的两个应用可以通过连接发送和接受字节流,当发送消息时,需要知道对方的ip和端口。
Socket类位于 java.net 包中。
- 构造方法
Socket(String host, int port)
:通过指定服务器的IP地址以及服务端口号创建Socket对象。
Socket client = new Socket("127.0.0.1", 5555);
- 部分方法
InputStream getInputStream()
:返回与当前socket相关的输入流对象。
InputStream is = client.getInputStream();
OutputStream getOutputStream()
:返回与当前socket相关的输出流对象。
OutputStream os = client.getOutputStream();
2、ServerSocket类
ServerSocket 是等待客户端的请求,一旦获得一个连接请求,就创建一个Socket实例来与客户端进行通信。
ServerSocket类位于 java.net 包中。
- 构造方法
ServerSocket(int port)
:通过指定服务端口号创建ServerSocket对象。
ServerSocket serversocket = new ServerSocket(5555);
- 部分方法
Socket accept()
:监听客户端的请求,并接受连接,返回一个Socket对象。
Socket socket = serversocket.accept();
四、Socket与ServerSocket通讯过程
基于TCP协议的通讯,客户端和服务器端都使用Socket对象获取输入流和输出流,使用IO流对象读写数据进行通讯。
1、通讯过程的简要描述
- 客户端
① 创建Socket对象,通过IP和端口请求连接某服务器。
② 使用Sockets对象获取输入输出流,可以向服务器端写数据,或者从服务器端读数据。
③ 关闭输入输出流,关闭socket对象。
- 服务端
① 创建ServerSocket对象,接受客户端的请求,返回一个Socket对象,与客户端建立了连接。
② 使用Sockets对象获取输入输出流,可以向客户端写数据,或者从客户端读数据。
③ 关闭相关资源。
2、代码案例
(1)单向:服务端读取数据,客户端发送数据。
- MyClientSocket.java(客户端)
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class MyClientSocket {
public static void main(String[] args) {
Socket client = null;
InputStream is = null;
DataInputStream dis = null;
try {
// client = new Socket("192.168.12.17", 7777);
// 创建Socket对象
client = new Socket("127.0.0.1", 5555);
// 通过Socket对象获取输入流
is = client.getInputStream();
dis = new DataInputStream(is);
// 对输入流进行读操作
System.out.println(dis.readUTF());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
try {
if (dis != null) {
dis.close();
}
if (is != null) {
is.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- MyServerSocket.java(服务端)
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServerSocket {
public static void main(String[] args) {
ServerSocket serversocket = null;
Socket socket = null;
OutputStream os = null;
DataOutputStream dos = null;
try {
// 创建ServerSocket对象
serversocket = new ServerSocket(5555);
System.out.println("服务器开始监听");
// 调用accept接收Socket对象
socket = serversocket.accept();
// 通过Socket对象获取输出流
os = socket.getOutputStream();
dos = new DataOutputStream(os);
// 对输出流进行写操作
dos.writeUTF("hello world");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
try {
if (dos != null) {
dos.close();
}
if (os != null) {
os.close();
}
if (socket != null) {
socket.close();
}
if (serversocket != null) {
serversocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(3)从服务端传递一个对象到客户端:在服务端序列化一个对象,在客户端反序列化这个对象。
- Apple.java(实体类)
import java.io.Serializable;
public class Apple implements Serializable {
private static final long serialVersionUID = 5214220254468067742L;
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Apple(String name, String color) {
super();
this.name = name;
this.color = color;
}
public Apple() {
super();
}
@Override
public String toString() {
return "Apple [name=" + name + ", color=" + color + "]";
}
}
- ObjectServerSocket.java(服务端)
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ObjectServerSocket {
public static void main(String[] args) {
ServerSocket serversocket = null;
Socket socket = null;
OutputStream os = null;
ObjectOutputStream oos = null;
try {
// 创建ServerSocket对象
serversocket = new ServerSocket(5555);
System.out.println("服务端开始监听");
// 调用accept接收Socket对象
socket = serversocket.accept();
System.out.println("客户端已连接服务端");
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
Apple apple = new Apple("青苹果", "绿色");
oos.writeObject(apple);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (os != null) {
os.close();
}
if (socket != null) {
socket.close();
}
if (serversocket != null) {
serversocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- ObjectClientSocket.java(客户端)
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class ObjectClientSocket {
public static void main(String[] args) {
Socket client = null;
InputStream is = null;
ObjectInputStream ois = null;
try {
// 创建Socket对象
client = new Socket("127.0.0.1", 5555);
// client = new Socket("192.168.12.17", 7777);
System.out.println("客户端已连接服务端");
is = client.getInputStream();
ois = new ObjectInputStream(is);
Object obj = ois.readObject();
if (obj instanceof Apple) {
Apple a = (Apple) obj;
System.out.println(a);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
if (is != null) {
is.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(3)双向:先是客户端写入数据,服务端读取数据,接着服务端写入数据,客户端读取数据,然后按此规律循环执行。
- LoopClientSocket.java(客户端)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class LoopClientSocket {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Socket client = null;
InputStream is = null;
DataInputStream dis = null;
OutputStream os = null;
DataOutputStream dos = null;
try {
// 创建Socket对象
client = new Socket("127.0.0.1", 5555);
//client = new Socket("192.168.12.17", 7777);
System.out.println("客户端已连接服务端");
// 通过Socket对象获取输出流和输入流
is = client.getInputStream();
dis = new DataInputStream(is);
os = client.getOutputStream();
dos = new DataOutputStream(os);
// 先对输出流进行写操作,再对输入流进行读操作
while (true) {
dos.writeUTF(sc.next());
dos.flush();
System.out.println("Client:" + dis.readUTF());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
if (is != null) {
is.close();
}
if (dos != null) {
dos.close();
}
if (os != null) {
os.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- LoopServerSocket.java(服务端)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class LoopServerSocket {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ServerSocket serversocket = null;
Socket socket = null;
OutputStream os = null;
DataOutputStream dos = null;
InputStream is = null;
DataInputStream dis = null;
try {
// 创建ServerSocket对象
serversocket = new ServerSocket(5555);
System.out.println("服务端开始监听");
// 调用accept接收Socket对象
socket = serversocket.accept();
System.out.println("客户端已连接服务端");
// 通过Socket对象获取输出流和输入流
os = socket.getOutputStream();
dos = new DataOutputStream(os);
is = socket.getInputStream();
// 先对输入流进行读操作,再对输出流进行写操作
while (true) {
dis = new DataInputStream(is);
System.out.println("Server:" + dis.readUTF());
dos.writeUTF(sc.next());
dos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dos != null) {
dos.close();
}
if (os != null) {
os.close();
}
if (dis != null) {
dis.close();
}
if (is != null) {
is.close();
}
if (socket != null) {
socket.close();
}
if (serversocket != null) {
serversocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(4)一个服务端与多个客户端通讯:先是多个客户端写入数据,一个服务端通过多线程读取每个客户端发过来的数据。多个客户端可以由多运行几次 MyClientSocket .java
实现。
- MyServerSocket .java(服务端)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class MyServerSocket {
public static void main(String[] args) {
ServerSocket serversocket = null;
Socket socket = null;
try {
// 创建ServerSocket对象
serversocket = new ServerSocket(8888);
System.out.println("服务器开始监听");
// 调用accept接收Socket对象
while (true) {
socket = serversocket.accept();
ClientThread mt = new ClientThread(socket);
new Thread(mt).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
try {
if (socket != null) {
socket.close();
}
if (serversocket != null) {
serversocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ClientThread implements Runnable {
private Socket socket;
public ClientThread(Socket socket) {
super();
this.socket = socket;
}
public ClientThread() {
super();
}
@Override
public void run() {
Scanner sc = new Scanner(System.in);
OutputStream os = null;
DataOutputStream dos = null;
InputStream is = null;
DataInputStream dis = null;
// 通过Socket对象获取输出流
try {
// 通过Socket对象获取输出流和输入流
os = socket.getOutputStream();
dos = new DataOutputStream(os);
is = socket.getInputStream();
dis = new DataInputStream(is);
// 先对输入流进行读操作,再对输出流进行写操作
while (true) {
System.out.println("请输入发送到客户端的数据:");
dos.writeUTF(sc.next());
System.out.println(Thread.currentThread().getName() + ": " + dis.readUTF());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (dos != null) {
dos.close();
}
if (is != null) {
is.close();
}
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- MyClientSocket .java(客户端)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class MyClientSocket {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Socket client = null;
InputStream is = null;
DataInputStream dis = null;
OutputStream os = null;
DataOutputStream dos = null;
try {
// 创建Socket对象
client = new Socket("192.168.12.21", 8888);
System.out.println("客户端已连接服务端");
// 通过Socket对象获取输出流和输入流
is = client.getInputStream();
dis = new DataInputStream(is);
os = client.getOutputStream();
dos = new DataOutputStream(os);
// 先对输出流进行写操作,再对输入流进行读操作
while (true) {
System.out.println("Server:" + dis.readUTF());
System.out.println("请输入发送到服务端的数据:");
dos.writeUTF(sc.next());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
if (is != null) {
is.close();
}
if (dos != null) {
dos.close();
}
if (os != null) {
os.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}