网络编程可以让程序与网络上的其他设备中的程序进行数据交互
常见的通信模式有两种:Client-Server(CS),Browser/Server(BS)
IP地址:设备在网络中的地址,是唯一的标识
端口:应用程序在设备中的唯一的标识
协议:数据在网络中传输的规则,常见的协议有UDP协议和TCP协议
IP(Internet Protocal);全称“互联网协议地址”,是分配给上网设备的唯一标志
常见的IP分类为:IPv4和IPv6
本地没有,会发至运行商的dns服务器,由域名返回IP地址
特殊的IP地址
此类表示Internet协议(IP)地址
package com.itxue.d1_inetAddress;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo1 {
public static void main(String[] args) throws Exception {
// 获取本机的地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
// 获取域名的ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
// 获取公网的IP对象
InetAddress ip3 = InetAddress.getByName("14.215.177.38");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
// 判断是否连通;ping 5s之前测试是否可通
System.out.println(ip3.isReachable(5000));
}
}
端口号:标识正在计算机设备上运行的进程(程序),被规定为一个16位的二进制,范围是0-65535
端口类型
注意:我们自己开发的程序选择注册端口,且一个设备中不能出现连个程序的端口号一样,否则出错
连接和通信数据的规则被称为网络通信协议
TCP三次握手确立关系
TCP四次挥手断开连接
1.
2.
package com.itxue.d2_udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*
接收端
*/
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动");
DatagramSocket socket = new DatagramSocket(9999);
byte[] buffer = new byte[64*1024];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
//等待接收数据
socket.receive(packet);
//取数数据
String rs = new String(buffer);
System.out.println(rs);
socket.close();
}
}
package com.itxue.d2_udp;
import sun.security.pkcs11.wrapper.CK_SSL3_KEY_MAT_OUT;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/*
发送端
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动");
// 创建发送端对象,发送端自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket();
// 创建一个数据包对象包装数据(韭菜盘子)
/*
public DatagramPacket(byte buf[], int length,
InetAddress address, int port)
*/
byte[] buffer = "我是小学生".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(),9999);
// 发送数据出去
socket.send(packet);
socket.close();
}
}
package com.itxue.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/*
发送端:多发 多收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动");
// 创建发送端对象,发送端自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入;");
String s = sc.nextLine();
if("exit".equals(s)){
System.out.println("离线成功");
socket.close();
break;
}
// 创建一个数据包对象包装数据(韭菜盘子)
byte[] buffer = s.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
// 发送数据出去
socket.send(packet);
}
}
}
package com.itxue.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/*
接收端
*/
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动");
DatagramSocket socket = new DatagramSocket(8888);
byte[] buffer = new byte[64*1024];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
//等待接收数据
while (true) {
socket.receive(packet);
//取数数据
String rs = new String(buffer);
System.out.println(rs);
}
}
}
package com.itxue.d4_udp3_broadcast.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/*
发送端:多发 多收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动");
// 创建发送端对象,发送端自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入;");
String s = sc.nextLine();
if("exit".equals(s)){
System.out.println("离线成功");
socket.close();
break;
}
// 创建一个数据包对象包装数据(韭菜盘子)
byte[] buffer = s.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);
// 发送数据出去
socket.send(packet);
}
}
}
package com.itxue.d5_udp4_multicast.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/*
接收端
*/
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动");
MulticastSocket socket = new MulticastSocket(9999);
socket.joinGroup(InetAddress.getByName("224.0.1.1"));
byte[] buffer = new byte[64*1024];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
//等待接收数据
while (true) {
socket.receive(packet);
//取数数据
String rs = new String(buffer);
System.out.println(rs);
}
}
}
package com.itxue.d5_udp4_multicast.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/*
发送端:多发 多收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动");
// 创建发送端对象,发送端自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入;");
String s = sc.nextLine();
if("exit".equals(s)){
System.out.println("离线成功");
socket.close();
break;
}
// 创建一个数据包对象包装数据(韭菜盘子)
byte[] buffer = s.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("224.0.1.1"), 9999);
// 发送数据出去
socket.send(packet);
}
}
}
package com.itxue.d6_socket1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
try {
// 创建Socket通信管道请求与服务器连接
// 参数一:服务端的IP地址 参数二:服务端的端口
socket = new Socket("127.0.0.1",7777);
// 2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级字节流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
ps.print("我是TCP的客户端,我已经与你连接,并发出邀请");
ps.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.itxue.d6_socket1;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo2 {
public static void main(String[] args) {
// 注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
// 调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
// 从socket管道中得到一个字节输入流
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
if((msg = br.readLine())!= null){
System.out.println(socket.getRemoteSocketAddress()+"说了"+msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.itxue.d6_socket1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
try {
// 创建Socket通信管道请求与服务器连接
// 参数一:服务端的IP地址 参数二:服务端的端口
socket = new Socket("127.1.0.0",7777);
// 2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级字节流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
ps.println("我是TCP的客户端,我已经与你连接,并发出邀请");
ps.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.itxue.d6_socket2.d6_socket1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo2 {
public static void main(String[] args) {
// 注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
// 调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
// 从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) {
e.printStackTrace();
}
}
}
package com.itxue.d6_socket2.d6_socket1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
try {
// 创建Socket通信管道请求与服务器连接
// 参数一:服务端的IP地址 参数二:服务端的端口
socket = new Socket("127.1.0.0",7777);
// 2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级字节流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入消息:");
String s = sc.nextLine();
ps.println(s);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.itxue.d7_socket3.d6_socket2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
public void run() {
try {
// 3. 从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()+"下线了!");
}
}
}
package com.itxue.d7_socket3.d6_socket2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo2 {
public static void main(String[] args) {
// 1.注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
while(true) {
// 2. 每接收到一个客户端的Socket管道,交给独立的线程负责读取线程
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"他上线了");
//开始创建线程处理socket
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.itxue.d7_socket3.d6_socket2;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
try {
// 创建Socket通信管道请求与服务器连接
// 参数一:服务端的IP地址 参数二:服务端的端口
socket = new Socket("127.1.0.0",7777);
// 2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级字节流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入消息:");
String s = sc.nextLine();
ps.println(s);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.itxue.d7_socket3.d6_socket2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
public void run() {
try {
// 3. 从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()+"下线了!");
}
}
}
package com.itxue.d8_socket4.d6_socket2;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class ServerDemo2 {
// 使用静态变量定义一个线程池对象
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) {
// 1.注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
while(true) {
// 2. 每接收到一个客户端的Socket管道,交给独立的线程负责读取线程
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"他上线了");
// 任务对象读取消息
Runnable target = new ServerReaderRunnable(socket);
pool.execute(target);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.itxue.d8_socket4.d6_socket2;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
try {
// 创建Socket通信管道请求与服务器连接
// 参数一:服务端的IP地址 参数二:服务端的端口
socket = new Socket("127.1.0.0",7777);
// 2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级字节流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入消息:");
String s = sc.nextLine();
ps.println(s);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端可以复用线程处理多个客户端,可以避免系统的瘫痪
适合客户端通信时长较短的场景
package com.itxue.d9_sms;
import com.itxue.d7_socket3.d6_socket2.ServerReaderThread;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerDemo2 {
// 定义一个静态的List集合存储当前全部在线的socket管道
public static List allOnlineSockets = new ArrayList<>();
public static void main(String[] args) {
// 1.注册端口
try {
ServerSocket serverSocket = new ServerSocket(9999);
while(true) {
// 2. 每接收到一个客户端的Socket管道,交给独立的线程负责读取线程
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"他上线了");
allOnlineSockets.add(socket);//上线完成
//开始创建线程处理socket
new ServerReadThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ServerReadThread extends Thread{
private Socket socket;
public ServerReadThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"收到消息"+line);
//把这个消息进行端口转发给全部的客户端socket管道
sendMsgToAll(line);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
ServerDemo2.allOnlineSockets.remove(socket);
}
}
private void sendMsgToAll(String msg) throws Exception{
for (Socket socket : ServerDemo2.allOnlineSockets) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
package com.itxue.d9_sms;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动");
Socket socket = new Socket("127.0.0.1",9999);
// 创建一个独立的线程专门负责这个客户端的信息(服务器随时可以转发信息过来!)
new ClientReaderThread(socket).start();
// 从socket管道中得到一个字节输出流管道
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请说:");
String msg = sc.nextLine();
ps.println(msg);
ps.flush();
}
}
}
class ClientReaderThread extends Thread{
private Socket socket;
public ClientReaderThread (Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null){
System.out.println("收到消息"+line);
}
} catch (Exception e) {
System.out.println("服务端把你踢出去了");
}
}
}
package com.itxue.d10_bs;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class bsServerDemo1 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(8080);
while (true){
Socket socket = ss.accept();
new ServerReaderThread(socket).start();
}
}
}
class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
// 浏览器已经与socket管道建立了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("《最可爱的人》");
ps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
优化为线程池
package com.itxue.d11_bsexpand.d10_bs;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class bsServerDemo1 {
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) throws Exception {
ServerSocket ss = new ServerSocket(8080);
while (true){
Socket socket = ss.accept();
pool.execute(new ServerReaderRunnable(socket));
}
}
}
class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
// 浏览器已经与socket管道建立了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("《最可爱的人》");
ps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}