本文是看完慕课网这组视频的学习笔记:https://www.imooc.com/learn/161
简介:
不同主机主机的应用程序要进行网络通信,则需要指定主机的IP地址以及程序所对应的端口号,端口号是用于区分同一主机上的不同程序。概括来说:Socket=IP地址+端口号,Socket是网络上程序双向通信链路的终结点,是TCP和UDP通信的基础。
常用的端口号:
http:80,ftp:21,telnet:23
Java中提供网络功能的四大类:
1.InetAddress:用于标识网络上的硬件资源
2.URL:统一资源定位符,用于直接读取或写入网络上的数据
3.Socket:使用TCP协议实现网络通信的Sockets相关类。
4.Datagram:使用UDP协议,将数据存在数据报中进行网络通信。
一、InetAddress:
没有构造方法,无法直接new一个对象进行使用,包含一些静态的方法,可以直接使用静态方法获取到实例。
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class InetAddressTest {
public static void main(String[] args) throws UnknownHostException {
//通过静态方法获取本机的InetAddress实例
InetAddress address = InetAddress.getLoopbackAddress();
System.out.println("计算机名:"+address.getHostName());
System.out.println("IP地址:"+address.getHostAddress());
//获取字节数组形式的IP地址
byte[] addressBytes = address.getAddress();
System.out.println("字节数组形式的IP:"+ Arrays.toString(addressBytes));
System.out.println(address);
//根据主机名获取InetAddress实例
InetAddress address2 = InetAddress.getByName("localhost");
System.out.println("计算机名:"+address2.getHostName());
System.out.println("IP地址:"+address2.getHostAddress());
//根据主机IP获取InetAddress实例
InetAddress address3 = InetAddress.getByName("127.0.0.1");
System.out.println("计算机名:"+address3.getHostName());
System.out.println("IP地址:"+address3.getHostAddress());
}
}
二、URL:
url用于标识网络上资源的地址,由协议名称和资源名称两部分组成,两部分之间由冒号隔开,如:http://www.baidu.com。http表示协议名称,www.baidu.com表示资源名称。
URL的常用方法:
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(String[] args) {
try {
URL baidu = new URL("http://www.baidu,com");
//通过已存在的实例创建新实例,第一个参数是实例名称,第二个参数是传递参数的名称
URL url = new URL(baidu,"/index.html?test=111");
System.out.println("协议:"+url.getProtocol());
System.out.println("主机信息:"+url.getHost());
//如未指定端口号,使用默认端口号,此时getPort方法的返回值为-1
System.out.println("端口号:"+url.getPort());
System.out.println("文件路径:"+url.getFile());
System.out.println("相对路径:"+url.getRef());
System.out.println("查询字符串:"+url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
使用URL获取网络上的资源:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
public class URLLoadWebPageInfo {
//创建一个URL实例
public static void main(String[] args) {
try {
URL url = new URL("http://www.baidu.com");
//通过openStream方法获取URL所表示资源的字节输入流
InputStream is = url.openStream();
//将字节输入流转换为字符输入流,并指定编码为utf-8
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();
}
}
}
三、使用Socket实现TCP网络通信:
TCP是面向连接的、有序的、可靠的以字节流发送数据的通信方式。Java网络编程中客户端主要用到Socket类,服务器端主要用到serverSocket类。
Socket通信实现步骤:
1.创建Socket和serverSocket
2.打开连接到Socket的输入/输出流
3.按照协议对Socket进行读/写操作
4.关闭输入输出流,关闭Socket。
Socket的TCP通信服务器端代码实现步骤:
1.创建ServerSocket对象,绑定监听端口。
2.通过accept()方法监听客户端请求
3.连接建立后,通过输入流获取到客户端的请求信息
4.通过输出流向客户端发送响应信息
5.关闭相关资源
Socket的TCP通信客户端代码实现步骤:
1.创建Socket对象,指定需要连接的服务器地址和端口号。
2.连接建立后,通过输出流向服务器端发送请求信息
3.通过输入流获取服务器端的响应信息
4.关闭相关资源
服务器端代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP协议的网络通信,实现用户登录
* 服务器端
*/
public class ServerSocketTest {
public static void main(String[] args) {
try {
//1、创建一个服务器端Socket,即ServerSocket,指定端口进行绑定和监听
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept()方法开始监听,等待客户端的链接
System.out.println("服务器即将启动等待客户端的连接");
Socket socket = serverSocket.accept();
//3.获取输入流,并读取客户端信息
InputStream is = socket.getInputStream();
//将字节流变为字符流
InputStreamReader isr = new InputStreamReader(is);
//为输入流添加缓冲
BufferedReader br = new BufferedReader(isr);
String data = null;
//循环读取客户端信息
while((data = br.readLine())!=null){
System.out.println("我是服务器端,客户端提交信息:"+data);
}
socket.shutdownInput();
//4.获取输出流,相应客户端的请求
OutputStream os = socket.getOutputStream();
//包装为打印流
PrintWriter pw = new PrintWriter(os);
pw.write("服务器端欢迎客户端");
pw.flush();//调用flush方法将缓冲输出
//5.关闭相关资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码:
import java.io.*;
import java.net.Socket;
public class ClientSocketTest {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("localhost",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 data = null;
while((data = br.readLine())!=null){
System.out.println("我是客户端,服务器端提交信息:"+data);
}
//4.关闭相关资源
is.close();
br.close();
pw.close();
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试时,需要先执行服务器端代码再执行客户端的代码。
服务器与多个客户端进行TCP通信:
应用多线程技术实现服务器与多个客户端之间的通信。
实现步骤:
1.创建ServerSocket对象,循环调用accept()方法等待客户端的链接。
2.客户端创建一个Socket,并请求和服务器端连接。
3.服务器端接收客户端请求,创建Socket与该客户端简历专线连接。
4.建立连接的两个socket在一个单独的线程上对话。
5.服务器等待新的链接
在上面的代码基础上修改。
服务器端代码:
服务器线程
package internet;
import java.io.*;
import java.net.Socket;
/**
* 服务器端线程处理类
*/
public class ServerThread extends Thread{
//和本线程相关的Socket
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
//响应客户端的请求
@Override
public void run() {
super.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 data = null;
//循环读取客户端信息
while((data = br.readLine())!=null){
System.out.println("我是服务器端,客户端提交信息:"+data);
}
socket.shutdownInput();
//获取输出流,相应客户端的请求
os = socket.getOutputStream();
//包装为打印流
pw = new PrintWriter(os);
pw.write("服务器端欢迎客户端");
pw.flush();//调用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 internet;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 基于TCP协议的网络通信,实现用户登录
* 服务器端
*/
public class ServerSocketTest {
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){
//2.调用accept()方法开始监听,等待客户端的链接
socket = serverSocket.accept();
//创建一个新线程
ServerThread serverThread = new ServerThread(socket);
//启动线程
serverThread.start();
count++;
System.out.println("客户端的数量为:"+count);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("当前客户端的IP:"+inetAddress.getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码不变:
package internet;
import java.io.*;
import java.net.Socket;
public class ClientSocketTest {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("localhost",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 data = null;
while((data = br.readLine())!=null){
System.out.println("我是客户端,服务器端提交信息:"+data);
}
//4.关闭相关资源
is.close();
br.close();
pw.close();
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、使用Datagram数据报相关类实现UDP网络通信:
UDP协议是无连接、不可靠、无序的,速度相对较快。以数据报作为数据传输的载体。数据传输时,首先将需要传输的数据定义为数据报,在数据报中指明需要达到的Socket(主机地址加端口号),然后再将数据发送出去。编程主要使用到DatagramPacket数据报包类和DatagramSocket进行端到端通信的类。
服务器端实现步骤:
1.创建DatagramSocket,指定端口号
2.创建DatagramPacket
3.接收客户端发送的信息
4.读取信息
客户器端实现步骤:
1.定义发送信息
2.创建DatagramPacket,包含要发送的信息
3.创建DatagramSocket
4.发送数据
服务器端代码:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpServer {
public static void main(String[] args) throws IOException {
//1.创建服务器端,DatagramSocket,指定端口
DatagramSocket datagramSocket = new DatagramSocket(8800);
//2.创建数据报,用于接受客户端发送的数据
byte[] data = new byte[1024];//创建字节数组,指定接收的数据包大小
DatagramPacket datagramPacket = new DatagramPacket(data,data.length);
//3.接收客户端发送的数组
System.out.println("服务器端已经启动等待客户端发送数据");
datagramSocket.receive(datagramPacket);//此方法在接收到数据报之前一直阻塞
//4.读取数据
String info = new String(data,0,datagramPacket.getLength());
System.out.println("我是服务器端,客户端说"+info);
/**
* 服务器端向客户端发送响应数据
*/
//1.定义客户端的地址、端口号和响应的数据
InetAddress address = datagramPacket.getAddress();
int port = datagramPacket.getPort();
byte[] data2 = "服务器端欢迎客户端访问".getBytes();
//2.创建数据报包含响应信息
DatagramPacket datagramPacket2 = new DatagramPacket(data2,data2.length,address,port);
//3.响应客户端
datagramSocket.send(datagramPacket2);
//4.关闭资源信息
datagramSocket.close();
}
}
客户端代码:
import java.io.IOException;
import java.net.*;
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 datagramPacket = new DatagramPacket(data,data.length,address,port);
//3.创建DatagramSocket对象
DatagramSocket datagramSocket = new DatagramSocket();
//4.向服务器发送数据
datagramSocket.send(datagramPacket);
/**
* 客户端接收服务器的响应信息
*/
//1.创建数据报,用于接收服务器端的响应信息
byte[] data2 = new byte[1024];
DatagramPacket datagramPacket2 = new DatagramPacket(data2,data2.length);
//2.接收服务器端的响应数据
datagramSocket.receive(datagramPacket2);
//3.读取服务器端响应的数据信息
String reply = new String(data2,0,datagramPacket2.getLength());
System.out.println("我是客户端,服务器端的响应信息为:"+reply);
//4.关闭资源
datagramSocket.close();
}
}
服务器与多个客户端进行UDP通信:
服务器代码:
服务器线程代码:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpServerThread extends Thread {
private DatagramSocket datagramSocket;
private DatagramPacket datagramPacket;
private String info;
private InetAddress address;
private int port;
public UdpServerThread(DatagramSocket datagramSocket, DatagramPacket datagramPacket) {
this.datagramSocket = datagramSocket;
this.datagramPacket = datagramPacket;
this.info = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
this.address=datagramPacket.getAddress();
this.port=datagramPacket.getPort();
}
@Override
public void run() {
super.run();
//接收客户端发送的数组
try {
//读取数据
System.out.println("我是服务器端,客户端说"+info);
/**
* 服务器端向客户端发送响应数据
*/
byte[] data2 = "服务器端欢迎客户端访问".getBytes();
//2.创建数据报包含响应信息
DatagramPacket datagramPacket2 = new DatagramPacket(data2,data2.length,address,port);
//3.响应客户端
datagramSocket.send(datagramPacket2);
} catch (IOException e) {
e.printStackTrace();
}finally {
//4.关闭资源信息
// if(datagramSocket!=null)
// datagramSocket.close();
}
}
}
服务器代码:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpServer {
public static void main(String[] args) throws IOException {
//1.创建服务器端,DatagramSocket,指定端口
DatagramSocket datagramSocket = new DatagramSocket(8800);
byte[] data = new byte[1024];//创建字节数组,指定接收的数据包大小
DatagramPacket datagramPacket = new DatagramPacket(data,data.length);
System.out.println("服务器端已经启动等待客户端发送数据");
int count = 0;
while(true){
datagramSocket.receive(datagramPacket);//此方法在接收到数据报之前一直阻塞
UdpServerThread udpServerThread =new UdpServerThread(datagramSocket,datagramPacket);
udpServerThread.start();
count++;
System.out.println("客户端的数量为:"+count);
InetAddress inetAddress = datagramPacket.getAddress();
System.out.println("当前客户端的IP:"+inetAddress.getHostAddress());
}
}
}
客户端代码不变:
import java.io.IOException;
import java.net.*;
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 datagramPacket = new DatagramPacket(data,data.length,address,port);
//3.创建DatagramSocket对象
DatagramSocket datagramSocket = new DatagramSocket();
//4.向服务器发送数据
datagramSocket.send(datagramPacket);
/**
* 客户端接收服务器的响应信息
*/
//1.创建数据报,用于接收服务器端的响应信息
byte[] data2 = new byte[1024];
DatagramPacket datagramPacket2 = new DatagramPacket(data2,data2.length);
//2.接收服务器端的响应数据
datagramSocket.receive(datagramPacket2);
//3.读取服务器端响应的数据信息
String reply = new String(data2,0,datagramPacket2.getLength());
System.out.println("我是客户端,服务器端的响应信息为:"+reply);
//4.关闭资源
datagramSocket.close();
}
}