java语言之网络编程
一、什么是网络
(1)概念
由点和线构成,表示诸多对象间的相互联系。
(2)计算机网络
为实现资源共享和信息传递,通过通信线路连接起来的若干主机(Host)。
(3)OSI参考模型
每层功能:
- 第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
- 第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
- 第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)。
- 第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)。
- 第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)。
- 第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
- 第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
(4)TCP/IP模型
每层功能:
- 第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
- 第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
- 第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
- 第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等。
二、TCP和UDP
(1)TCP:传输控制协议
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连接的过程需要三次握手,断开连接的过程需要四次挥手。
(2)UDP:用户数据报协议
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小64KB。
三、Socket编程
(1)Socket(套接字)是网络中的一个通信节点。
(2)分为客户端Socket与服务器ServerSocket。
(3)通信要求:IP地址 + 端口号。
(1)TCP实现客户端与服务器之间的一对一通信
案例演示1:一对一聊天,通信不断
Server类:
public class Server {
public static void main(String[] args) throws IOException {
//1、创建ServerSocket对象并指定端口号
ServerSocket server = new ServerSocket(2007);
System.out.println("服务端启动成功!");
//2、调用accept(),接收客户端请求,阻塞方法(如果没有客户端请求,则阻塞)
Socket socket = server.accept();
System.out.println("客户端连接成功!");
Scanner scanner = new Scanner(System.in);
OutputStream os = null;
InputStream is = null;
try {
while (true) {
//3、获取输入流,读取客户端发送的数据
is = socket.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
//4、将客户端发送的数据输出到控制台
System.out.println("客户端:" + new String(b, 0, len));
//5、获取输出流,发送数据给客户端
os = socket.getOutputStream();
os.write(scanner.next().getBytes());
}
}finally {
os.close();
is.close();
}
}
}
Client类:
public class Client {
public static void main(String[] args) throws IOException {
//1、创建Socket对象,并指定服务端的ip和端口号
Socket socket = new Socket("127.0.0.1",2007);
Scanner scanner = new Scanner(System.in);
OutputStream os = null;
InputStream is = null;
try{
while (true){
//2、获取输出流,发送数据给服务端端
os = socket.getOutputStream();
os.write(scanner.next().getBytes());
//3、获取输入流,读取服务端发送的数据
is = socket.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
//4、将服务端发送的数据输出到控制台
System.out.println("服务端:" + new String(b,0,len));
}
}finally {
os.close();
is.close();
}
}
}
案例演示2:利用线程实现读写不冲突
Server类:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
System.out.println("服务端开启成功!");
Socket socket = server.accept();
System.out.println("客户端连接成功!");
new ReaderThread("客户端",socket).start();
new WriterThread("服务端",socket).start();
}
}
Client类:
public class Client2 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
new ReaderThread("服务端",socket).start();
new WriterThread("客户端",socket).start();
}
}
ReaderThread线程类:
public class ReaderThread extends Thread {
private Socket socket;
private String name;
public ReaderThread(String name, Socket socket){
this.name = name;
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
try {
is = socket.getInputStream();
byte[] b = new byte[1024];
while (true) {
int len = is.read(b);
System.out.println(new String(b, 0, len));
}
} catch (IOException e) {
System.out.println(name + "已关闭!");
} finally {
try {
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
WriterThread线程类:
public class WriterThread extends Thread {
private String name;
private Socket socket;
Scanner scanner = new Scanner(System.in);
public WriterThread(String name, Socket socket){
this.name = name;
this.socket = socket;
}
@Override
public void run() {
OutputStream os = null;
try {
os = socket.getOutputStream();
while (true) {
os.write((name+":"+scanner.next()).getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
案例演示3:字符流一对一通信,读写不冲突
Server类:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
System.out.println("服务端开启成功!");
Socket socket = server.accept();
System.out.println("客户端连接成功!");
new ReaderThread("客户端",socket).start();
new WriterThread("服务端",socket).start();
}
}
Client类:
public class Client2 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
new ReaderThread("服务端",socket).start();
new WriterThread("客户端",socket).start();
}
}
ReaderThread线程类:
public class ReaderThread1 extends Thread {
private String name;
BufferedReader br;
public ReaderThread1(String name,Socket socket) throws IOException {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.name = name;
}
@Override
public void run() {
String str = null;
try {
while(true){
str = br.readLine();
if(str != null){
System.out.println(str);
}
}
} catch (IOException e) {
System.out.println(name + "已关闭!");
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
WriterThread线程类:
public class WriterThread1 extends Thread {
private String name;
BufferedWriter bw;
BufferedReader br;
public WriterThread1(String name,Socket socket) throws IOException {
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
br = new BufferedReader(new InputStreamReader(System.in));
this.name = name;
}
@Override
public void run() {
try {
while (true) {
bw.write(name + ":" + br.readLine());
bw.newLine();
bw.flush();
}
} catch (IOException e) {
System.out.println(name + "已关闭!");
}finally {
try {
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(2)UDP实现客户端与服务器之间的一对一通信
案例演示1:一对一聊天,通信不断
Client1类:
public class Client1 {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//创建一个指定端口号的 UDP 套接字
DatagramSocket socket = new DatagramSocket(8888);
while (true) {
//发送数据给其他主机
//把数据保存在数组中
byte[] b = scanner.next().getBytes();
//创建DatagramPacket对象,里面的参数为(数组,数组的长度,接收的主机IP,接收的主机端口号)
DatagramPacket packet = new DatagramPacket(b, b.length, InetAddress.getByName("127.0.0.1"), 9999);
//开始发送
socket.send(packet);
//接收其他主机发送过来的数据
//先创建存放数据的数组和DatagramPacket对象
b = new byte[1024];
packet = new DatagramPacket(b,b.length);
//接收数据
socket.receive(packet);
//解析数据并输出
System.out.println("Client2:" + new String(packet.getData(),0, packet.getLength()));
}
}
}
Client2类:
public class Client2 {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//创建一个指定端口号的 UDP 套接字
DatagramSocket socket = new DatagramSocket(9999);
while (true) {
//接收其他主机发送过来的数据
//先创建存放数据的数组和DatagramPacket对象
byte[] b = new byte[1024];
DatagramPacket packet = new DatagramPacket(b, b.length);
//接收数据
socket.receive(packet);
//解析数据并输出
System.out.println("Client1:" + new String(packet.getData(), 0, packet.getLength()));
//发送数据给其他主机
//把数据保存在数组中
b = scanner.next().getBytes();
//创建DatagramPacket对象,里面的参数为(数组,数组的长度,接收的主机IP,接收的主机端口号)
packet = new DatagramPacket(b, b.length, InetAddress.getByName("127.0.0.1"), 8888);
//开始发送
socket.send(packet);
}
}
}
案例演示2:利用线程实现读写不冲突
Client3类:
public class Client3 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(8888);
Scanner scanner = new Scanner(System.in);
new ReadThread(socket,"Client4说").start();
new WriteThread(socket,"127.0.0.1",9999).start();
}
}
Client4类:
public class Client4 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9999);
Scanner scanner = new Scanner(System.in);
new ReadThread(socket,"Client3说").start();
new WriteThread(socket,"127.0.0.1",8888).start();
}
}
ReadThread线程类:
public class ReadThread extends Thread {
DatagramSocket socket;
String name;
public ReadThread(DatagramSocket socket,String name) {
this.socket = socket;
this.name = name;
}
@Override
public void run() {
try {
while (true) {
byte[] b = new byte[1024];
DatagramPacket packet = new DatagramPacket(b, b.length);
socket.receive(packet);
System.out.println(name + ":" + new String(packet.getData(), 0, packet.getLength()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
WriteThread线程类:
public class WriteThread extends Thread {
DatagramSocket socket;
String ip;
int duankou;
public WriteThread(DatagramSocket socket,String ip,int duankou) {
this.ip = ip;
this.duankou = duankou;
this.socket = socket;
}
@Override
public void run() {
Scanner scanner = new Scanner(System.in);
try {
while (true) {
byte[] b = scanner.next().getBytes();
DatagramPacket packet = new DatagramPacket(b, b.length, InetAddress.getByName(ip), duankou);
socket.send(packet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}