目录
网络编程概述
网络通信三要素
三要素概述、要素一:IP地址
IP地址操作类-inetAddress
要素二:端口号
要素三:协议
UDP通信
UDP通信:快速入门
实现UDP一发一收
/**
* 接受端 服务端
*/
public class ClicentDemo2 {
public static void main(String[] args) throws IOException {
//1、创建接收端对象:注册端口(人)
DatagramSocket socket = new DatagramSocket(8888);
//2、创建一个数据包接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
//3、等待接收数据
socket.receive(packet);
int len = packet.getLength();
//4、取出数据
String s = new String(buffer,0,len);
System.out.println("收到了:" + s);
socket.close();
}
}
/**
* 发送端 一发一收
*/
public class ClicentDemo1 {
public static void main(String[] args) throws Exception {
//1、创建发送端对象 发送端自带默认端口号
DatagramSocket socket = new DatagramSocket();
//2、创建数据包对象封装对象(韭菜盘子)
/*
* 参数一:封装要发送的数据(韭菜)
* 参数二:数据大小
* 参数三:对方ip地址
* 参数四:服务端端口*/
byte[] buffer = "我是一颗韭菜".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(),8888);
//3、发送数据
socket.send(packet);
socket.close();
}
}
UDP通信:多发多收
/**
* 接受端 服务端 多发多收
*/
public class ClicentDemo2 {
public static void main(String[] args) throws IOException {
System.out.println("=====服务端启动====");
//1、创建接收端对象:注册端口(人)
DatagramSocket socket = new DatagramSocket(8888);
//2、创建一个数据包接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
while (true) {
//3、等待接收数据
socket.receive(packet);
int len = packet.getLength();
//4、取出数据
String s = new String(buffer,0,len);
System.out.println("收到了来自:" + packet.getAddress() + ",对方端口是" + packet.getPort() + "的消息:" + s);
}
}
}
/**
* 发送端 多发多收
*/
public class ClicentDemo1 {
public static void main(String[] args) throws Exception {
//1、创建发送端对象 发送端自带默认端口号
DatagramSocket socket = new DatagramSocket();
//2、创建数据包对象封装对象(韭菜盘子)
/*
* 参数一:封装要发送的数据(韭菜)
* 参数二:数据大小
* 参数三:对方ip地址
* 参数四:服务端端口*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
byte[] buffer = msg.getBytes();
if ("exit".equals(msg)){
System.out.println("离线成功!");
socket.close();
break;
}
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(),8888);
//3、发送数据
socket.send(packet);
}
}
}
UDP通信-广播、组播
发送端:
接收端:
TCP通信-快速入门
编写客户端代码
public class Client {
public static void main(String[] args) {
//1、创建Socket通信管道请求有服务器的连接
//参数一:服务端的IP地址
//参数二:服务端的端口
try {
Socket socket = new Socket("127.0.0.1",7777);
//2、从socket管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
ps.println("我是TCP的客户端,我已经与你对接,并发出邀请。");
ps.flush();
//关闭程序
//socket.close(); 此处可不直接关闭资源,防止传输出错。
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
编写服务端代码、原理分析
/**
* 目标:开发Socket网络编程入门代码的服务器,实现接受消息
*/
public class Server {
public static void main(String[] args) {
try {
System.out.println("===服务端启动成功===");
//1、注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//2、必须调用accept方法,等等待接收客户端的Socket连接请求,建立Socket管道
Socket socket = serverSocket.accept();
//3、从socket管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//4、把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
if ((msg = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
TCP通信-多发多收消息
发送端/客户端进行部分修改
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说");
String msg = sc.nextLine();
//4.发送消息
ps.println(msg);
ps.flush();
}
接收端进行部分修改
while ((msg = br.readLine()) != null)
TCP通信-同时接受多个客户端消息
/**
* 目标:开发Socket网络编程入门代码的服务器,实现可以同时接收多个客户端消息
*/
public class Server {
public static void main(String[] args) {
try {
System.out.println("===服务端启动成功===");
//1、注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环由主线程负责不断接收客户端的Socket管道连接。
while (true) {
//2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取。
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "上线了!!!");
//3、开始创建独立线程处理Socket
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息。
String msg;
while ((msg = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了!!"); }
}
}
TCP通信-使用线程池优化
/**
* 目标:使用线程池优化,实现通信。
*/
public class Server {
//使用静态变量记住一个线程池对象
private static ExecutorService pool = new ThreadPoolExecutor(3,5, 6,TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
System.out.println("===服务端启动成功===");
//1、注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环由主线程负责不断接收客户端的Socket管道连接。
while (true) {
//2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取。
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "上线了!!!");
Runnable target = new ServerReaderThread(socket);
pool.execute(target);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息。
String msg;
while ((msg = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了!!");
}
}
}
客户端代码无需修改
TCP通信案例-即时通信
/**
* 目标:即时通讯
* 1、客户端发送消息
* 1、客户端随时可能需要收到消息
*/
public class Client {
public static void main(String[] args) {
//1、创建Socket通信管道请求有服务器的连接
//参数一:服务端的IP地址
//参数二:服务端的端口
try {
System.out.println("===客户端启动===");
Socket socket = new Socket("127.0.0.1",7777);
//创建一个独立的线程专门负责整个客户端的读消息(服务器随时可能发消息过来)
new ClientReadrThread(socket).start();
//2、从socket管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说");
String msg = sc.nextLine();
//4.发送消息
ps.println(msg);
ps.flush();
}
//关闭程序
//socket.close(); 此处可不直接关闭资源,防止传输出错。
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
class ClientReadrThread extends Thread{
private Socket socket;
public ClientReadrThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息。
String msg;
while ((msg = br.readLine()) != null){
System.out.println("收到消息" + msg);
}
} catch (IOException e) {
System.out.println("服务端把你踢出去了....");
}
}
}
/**
* 目标:即时通信
*/
public class Server {
//定义一个静态的List集合存储当前全部在线的socket管道
public static List<Socket> allOnlineSocket = new ArrayList<>();
public static void main(String[] args) {
try {
System.out.println("===服务端启动成功===");
//1、注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环由主线程负责不断接收客户端的Socket管道连接。
while (true) {
//2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取。
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "上线了!!!");
allOnlineSocket.add(socket);
//3、开始创建独立线程处理Socket
new ServerReaderRunnable(socket).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public class ServerReaderRunnable extends Thread{
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息。
String msg;
while ((msg = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
//把这个消息进行端口转发给全部的客户端Socket管道
sendMsgToall(msg);
}
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了!!");
Server.allOnlineSocket.remove(socket);
}
}
private void sendMsgToall(String msg) throws IOException {
for (Socket socket : Server.allOnlineSocket) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
TCP通信案例-模拟BS系统
public class ServerReaderRunnable extends Thread{
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//浏览器 已经与本线程建立了Socket管道
//响应消息给浏览器显示
PrintStream ps = new PrintStream(socket.getOutputStream());
//必须响应HTTP协议格式数据,否则浏览器不认识消息
ps.println("HTTP/1.1 200 OK"); //协议类型和版本 响应成功的消息!
ps.println("Content-Type:text/html;charset=UTF-8"); //响应的数据类型:文本、网页
ps.println(); //必须发送一个空行
ps.println("<span style='color:red;font-size:90px'>澳门倒闭人啊!!!</span>");
ps.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}