1、概述
- TCP/IP是目前世界上应用最为广泛的协议,是以TCP和IP为基础的不同层次上多个协议的集合,也称:TCP/IP协议族或TCP/IP协议栈
- TCP:Transmission Control Protocol 传输控制协议
- IP:Internet Protocol 互联网协议
- 为实现网络中不同计算机之间的通信,每台机器都必须有一个唯一的标识-IP地址
- IP地址格式:数字型,如:192.168.0.1
- 端口号用于区分不同应用程序
- 端口号范围为065535,其中01023为系统所保留
- IP地址和端口号组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。
- Http:80
- FTP:21
- Telnet:23
2、Java中的网络支持
针对网络通信的不同层次,Java提供的网络功能有四大类:
- InetAddress:用于标识网络上的硬件资源。
- URL:统一资源定位符,通过URL可以直接读取或写入网络上的数据。
- Sockets:使用TCP协议实现网络通信的Socket相关的类。
- Datagram:使用UDP协议,将数据保存在数据报中,通过网络进行通信。
3、InetAddress类
- 1、InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址。
package com.lord.quick;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* InetAddress类
*/
public class SocketTest {
public static void main(String[] args) throws UnknownHostException {
// 获取本机的InetAddress实例
InetAddress address = InetAddress.getLocalHost();
System.out.println("计算机名:" + address.getHostName());
System.out.println("IP地址:" + address.getHostAddress());
// 根据机器名获取InetAddress实例
InetAddress address2 = InetAddress.getByName("Lord");
System.out.println("计算机名:" + address2.getHostName());
System.out.println("IP地址:" + address2.getHostAddress());
}
}
4、URL
- URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址。
- URL由两部分组成:协议名称和资源名称,中间用冒号隔开。
package com.lord.quick;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
/**
* URL常用方法
*/
public class SocketTest {
public static void main(String[] args) throws UnknownHostException {
try {
// 创建URL实例
URL zhihu = new URL("https://zhuanlan.zhihu.com");
// ?号后面表示参数,#号后面表示锚点
URL url = new URL(zhihu, "index.html?username=tom#test");
System.out.println("协议:" + url.getProtocol());
System.out.println("主机:" + url.getHost());
// 如果未指定端口号,则使用默认端口号,此时,getPort()方法返回值为-1
System.out.println("端口:" + url.getPort());
System.out.println("文件路径:" + url.getPath());
System.out.println("文件名:" + url.getFile());
System.out.println("相对路径:" + url.getRef());
System.out.println("查询字符串:" + url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
- 通过URL对象的openStream()方法可以得到指定资源的输入流。
- 通过输入流可以读取、访问网络上的数据。
package com.lord.quick;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
/**
* 使用URL读取网页内容
*/
public class SocketTest {
public static void main(String[] args) throws UnknownHostException {
try {
// 创建一个URL实例
URL url = new URL("http://www.baidu.com");
// 通过URL的openStream方法获取URL对象所表示的资源的字节输入流
InputStream is = url.openStream();
// 将字节输入流转换为字符输入流
InputStreamReader isr = new InputStreamReader(is, "utf-8");
// 为字符输入流添加缓冲
BufferedReader br = new BufferedReader(isr);
// 读取数据
String data = br.readLine();
// 循环读取数据
while (data != null) {
// 输出数据
System.out.println(data);
data = br.readLine();
}
br.close();
isr.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5、基于TCP协议的Socket通信,实现用户登录(单线程)
- 服务器端
package com.lord.quick;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP协议的Socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
// 1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("***服务器即将启动,等待客户端的连接***");
// 2、调用accept()开始监听,等待客户端连接
Socket socket = serverSocket.accept();
// 3、获取输入流,并读取客户端信息
// 字节输入流
InputStream is = socket.getInputStream();
// 将字节流转换为字符流
InputStreamReader isr = new InputStreamReader(is);
// 为输入流添加缓冲
BufferedReader br = new BufferedReader(isr);
// 循环读取客户端的信息
String info = null;
while ((info = br.readLine()) != null) {
System.out.println("我是服务器,客户端说:" + info);
}
// 关闭输入流
socket.shutdownInput();
// 4、获取输出流,响应客户端的请求
OutputStream os = socket.getOutputStream();
// 包装为打印流
PrintWriter pw = new PrintWriter(os);
pw.write("欢迎您!");
// 调用flush方法,将缓存输出
pw.flush();
// 5、关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 客户端
package com.lord.quick;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 基于TCP协议的Socket通信,实现用户登录
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
// 1、创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("127.0.0.1", 8888);
// 2、获取输出流,向服务器端发送信息
// 字节输出流
OutputStream os = socket.getOutputStream();
// 将输出流包装成打印流
PrintWriter pw = new PrintWriter(os);
pw.write("用户名:admin;密码:123");
pw.flush();
// 关闭输出流
socket.shutdownOutput();
// 3、获取输入流,并读取服务端的响应内容
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while ((info = br.readLine()) != null) {
System.out.println("我是客户端,服务器说:" + info);
}
// 4、关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6、基于TCP协议的Socket通信,实现用户登录(多线程)
- 服务器端线程处理类
package com.lord.quick;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
/**
* 服务器端线程处理类
*/
public class ServerThread extends Thread {
// 和本线程相关的处理类
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
// 执行线程操作,响应客户端请求
@Override
public void run() {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
try {
// 获取输入流,并读取客户端信息
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
// 循环读取客户端的信息
String info = null;
while ((info = br.readLine()) != null) {
System.out.println("我是服务器,客户端说:" + info);
}
// 关闭输入流
socket.shutdownInput();
// 获取输出流,响应客户端的请求
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.write("欢迎您!");
// 调用flush方法,将缓存输出
pw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭资源
if (pw != null) {
pw.close();
}
if (os != null) {
os.close();
}
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
if (is != null) {
is.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 服务器端
package com.lord.quick;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP协议的Socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
// 1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("***服务器即将启动,等待客户端的连接***");
Socket socket = null;
// 记录客户端的数量
int count = 0;
// 循环监听等待客户端的连接
while (true) {
// 调用accept()开始监听,等待客户端连接
socket = serverSocket.accept();
// 创建一个新的线程
ServerThread serverThread = new ServerThread(socket);
// 启动线程
serverThread.start();
// 统计客户端的数量
count++;
System.out.println("客户端的数量:" + count);
InetAddress address = socket.getInetAddress();
System.err.println("当前客户端的IP:" + address.getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 客户端
package com.lord.quick;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 基于TCP协议的Socket通信,实现用户登录
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
// 1、创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("127.0.0.1", 8888);
// 2、获取输出流,向服务器端发送信息
// 字节输出流
OutputStream os = socket.getOutputStream();
// 将输出流包装成打印流
PrintWriter pw = new PrintWriter(os);
pw.write("用户名:admin;密码:123");
pw.flush();
// 关闭输出流
socket.shutdownOutput();
// 3、获取输入流,并读取服务端的响应内容
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while ((info = br.readLine()) != null) {
System.out.println("我是客户端,服务器说:" + info);
}
// 4、关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7、UDP编程
- UDP协议(用户数据报协议)是无连接、不可靠的、无序的
- UDP协议以数据报作为数据传输的载体
- 使用UDP进行数据传输时,首先需要讲要传输的数据定义成数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口号),然后再将数据报发送出去
- DatagramPacket:表示数据报包
- DatagramSocket:表示端到端通信的类
8、基于UDP协议的Socket通信,实现用户登录
- 服务器端
package com.lord.quick;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 基于UDP协议的Socket通信,实现用户登录
* 服务器端
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
/**
* 接收客户端发送的数据
*/
// 1、创建服务器端DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
// 2、创建数据报,用于接收客户端发送的数据
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
// 3、接收客户端发送的数据,此方法在接收到数据报之前会一直阻塞
System.out.println("***服务器已经启动,等待客户端发送数据***");
socket.receive(packet);
// 4、读取数据
String info = new String(data, 0, packet.getLength());
System.out.println("我是服务器,客户端说:" + info);
/**
* 向客户端响应数据
*/
// 1、定义客户端的地址、端口、数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "欢迎您!".getBytes();
// 2、创建数据报,包含响应的信息
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
// 3、响应客户端
socket.send(packet2);
// 关闭资源
socket.close();
}
}
- 客户端
package com.lord.quick;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 基于UDP协议的Socket通信,实现用户登录
* 客户端
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
/**
* 向服务器端发送数据
*/
// 1、定义服务器的地址、端口号、数据
InetAddress address = InetAddress.getByName("localhost");
int port = 8800;
byte[] data = "用户名:admin;密码:123".getBytes();
// 2、创建数据报,包含发送的信息
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
// 3、创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
// 4、向服务器端发送数据报
socket.send(packet);
/**
* 接收服务器端响应的数据
*/
// 1、创建数据报,用于接受服务器端响应的数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
// 2、接收服务器端响应的数据
socket.receive(packet2);
// 3、读取数据
String reply = new String(data2, 0, packet2.getLength());
System.out.println("我是客户端,服务器说:" + reply);
// 关闭资源
socket.close();
}
}
网友评论