一. 网络编程基本概念
-
ISO(开放系统互联参考模型)七层协议模型
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 数据链路层
- 物理层
-
b/s和c/s
- b/s:浏览器/服务器(公网访问)
- c/s:客户端/服务器(内网)
-
TCP/IP参考模型
- 应用层(Telenet,FTP,SMTP,DNS,HTTP)
- 传输层(TCP/UDP)
- 网络层(IP)
- 物理+数据链路层
- 应用层和传输层之间使用套接字(Socket)进行连接
-
TCP是面向连接的,传输数据安全,稳定,效率相对较低
- 一种面向连接的,可靠的,基于字节流的运输层通信协议
- 特点:
- 面向连接
- 点到点通信
- 高可靠性
- 占用系统资源多,效率低
-
UDP是面向无连接的,传输数据不安全,效率较高.
- 一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务
- 特点:
- 非面向连接,传输不可靠,可能丢失
- 发送不管对方是否准备好,接收方收到也不确认
- 可以广播发送
- 非常简单的协议,开销小
-
TCP建立连接三部:
- 客户端发送syn(同步)报文,加原始的tcp连接序号
- 服务器接收到客户端的syn报文,返回syn+ack报文,同时tcp序号加一
- 客户端也返回一个ack报文给服务器,tcp序列化加一.
- 三次握手完成
-
常用端口号(1024以下留给公用)
- 80:http
- 21:sftp
- 8080:tomcat
- 1521:oracle
- 3306:mysql
- 443:https
二. URL基本用法
-
URI(Universal Resource Identifier)统一资源标识符
- URL(Universal Resource Locator)统一资源定位符
- URN(Universal Resource Name) 统一资源名称
-
爬虫基本原理
package com.it; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; /** * 网络爬虫+模拟浏览器 * @author ZRY * @version 1.0 */ public class SpiderTest02 { public static void main(String[] args) { try { // URL url = new URL("https://www.jd.com"); URL url = new URL("https://www.dianping.com"); //下载资源 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.34"); // InputStream is = url.openStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8")); String path = "Z://Desktop//11.txt"; File file = new File(path); if (file.exists()){ file.delete(); } String msg = null; FileOutputStream fileOutputStream = new FileOutputStream(file); OutputStreamWriter outputStreamWriter =new OutputStreamWriter(fileOutputStream); BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); while (null!=(msg=bufferedReader.readLine())){ System.out.println(msg); //写入文件 bufferedWriter.write(msg); bufferedWriter.newLine(); } bufferedReader.close(); bufferedWriter.close(); } catch (Exception e){ e.printStackTrace(); } } }
三. UDP编程
-
基本概念
- DatagramSocket:用于发送或者接收数据包的套接字
- DatagramPacket:数据包
-
客户端发送udp数据
package com.it.udp; import com.sun.xml.internal.ws.wsdl.writer.document.http.Address; import javax.xml.crypto.Data; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; /** * 发送端 * * 1. 使用datagramSocket 指定端口 创建接收端 * * 2. 准备容器 封装成datagramPacket * * 3. 阻塞式接收包裹receive * * 4. 分析数据 * @author ZRY * @version 1.0 */ public class UdpClient { public static void main(String[] args) { System.out.println("发送方启动中...."); try { DatagramSocket client = new DatagramSocket(8888); String data = "你好,java"; byte[] datas = data.getBytes(); DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999)); client.send(packet); //释放资源 client.close(); } catch (Exception e) { e.printStackTrace(); } } }
-
服务器接收udp数据
package com.it.udp; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /** * 接收端 * 1. 使用datagramSocket 指定端口 创建接收端 * 2. 准备容器 封装成datagramPacket * 3. 阻塞式接收包裹receive * 4. 分析数据 * @author ZRY * @version 1.0 */ public class UdpServer { public static void main(String[] args) { System.out.println("接收方启动中..."); try { DatagramSocket server = new DatagramSocket(9999); byte[] container = new byte[1024*60]; DatagramPacket packet = new DatagramPacket(container,0,container.length); server.receive(packet); byte[] datas = packet.getData(); int len = packet.getLength(); System.out.println("--"+new String(datas,0,len)); server.close(); } catch (Exception e) { e.printStackTrace(); } } }
-
客户端通过UDP协议发送file文件
package com.it.udp; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; /** * 发送端 * * 1. 使用datagramSocket 指定端口 创建接收端 * * 2. 准备容器 封装成datagramPacket * * 3. 阻塞式接收包裹receive * * 4. 分析数据 * @author ZRY * @version 1.0 */ public class UdpFileClient { public static void main(String[] args) { System.out.println("发送方启动中...."); try { DatagramSocket client = new DatagramSocket(8888); //2.准备数据 转化为字节数组 byte[] datas = IOFileUtils.byteArrayFile("src/img/1.jpg"); DatagramPacket packet = new DatagramPacket(datas,datas.length,new InetSocketAddress("localhost",9999)); client.send(packet); //释放资源 client.close(); } catch (Exception e) { e.printStackTrace(); } } }
-
服务端通过UDP协议接收file文件
package com.it.udp; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * 接收端 * 1. 使用datagramSocket 指定端口 创建接收端 * 2. 准备容器 封装成datagramPacket * 3. 阻塞式接收包裹receive * 4. 分析数据 * 5. 将字节数组还原为基本数据类型 * @author ZRY * @version 1.0 */ public class UdpFileServer { public static void main(String[] args) { System.out.println("接收方启动中..."); try { DatagramSocket server = new DatagramSocket(9999); //准备容器 byte[] container = new byte[1024*60]; DatagramPacket packet = new DatagramPacket(container,container.length); //阻塞式接收数据 server.receive(packet); //分析数据 byte[] datas = packet.getData(); int len = packet.getLength(); IOFileUtils.byteArrayToFile(datas,"src/img/1-1.jpg"); server.close(); } catch (Exception e) { e.printStackTrace(); } } }
-
文件转化字节数组工具
package com.it.udp; import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; import java.io.*; /** * @author ZRY * @version 1.0 */ public class IOFileUtils { /** * 将文件转化为字节数组 * @param filepath * @return */ public static byte[] byteArrayFile(String filepath){ //1.创建源于目的地 File file = new File(filepath); byte[] dest= null; //2.选择流 InputStream is =null; ByteArrayOutputStream baos = new ByteArrayOutputStream((int) file.length()); try { is=new FileInputStream(file); baos = new ByteArrayOutputStream(); dest = new byte[1024*60]; int len = 0; while ((len=is.read(dest))!=-1){ baos.write(dest,0,len); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); }finally { try { if (is!=null){ is.close(); } if (baos!=null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } public static void byteArrayToFile(byte[] src,String filepath){ FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(new File(filepath)); fileOutputStream.write(src,0,src.length); System.out.println("保存成功..."); } catch (IOException e) { e.printStackTrace(); }finally { try { if (fileOutputStream!=null){ fileOutputStream.close(); } }catch (IOException e){ e.printStackTrace(); } } } }
-
客户端通过UDP协议发送基本数据类型
package com.it.udp; import com.sun.corba.se.impl.oa.poa.AOMEntry; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; /** * 发送端 * * 1. 使用datagramSocket 指定端口 创建接收端 * * 2. 准备容器 封装成datagramPacket * * 3. 阻塞式接收包裹receive * * 4. 分析数据 * @author ZRY * @version 1.0 */ public class UdpTypeClient { public static void main(String[] args) { System.out.println("发送方启动中...."); try { DatagramSocket client = new DatagramSocket(8888); ByteArrayOutputStream bs = new ByteArrayOutputStream(); DataOutputStream ds = new DataOutputStream(new BufferedOutputStream(bs)); ds.writeUTF("你好,java"); ds.writeInt(18); ds.writeChar('v'); ds.writeBoolean(false); ds.flush(); System.out.println("bs="+bs); System.out.println("ds="+ds); byte[] datas = bs.toByteArray(); System.out.println("==="+datas); System.out.println("=="+datas.length); DatagramPacket packet = new DatagramPacket(datas,datas.length,new InetSocketAddress("localhost",9999)); client.send(packet); //释放资源 client.close(); bs.close(); ds.close(); } catch (Exception e) { e.printStackTrace(); } } }
-
服务器通过UDP协议接收基本数据类型
package com.it.udp; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * 接收端 * 1. 使用datagramSocket 指定端口 创建接收端 * 2. 准备容器 封装成datagramPacket * 3. 阻塞式接收包裹receive * 4. 分析数据 * 5. 将字节数组还原为基本数据类型 * @author ZRY * @version 1.0 */ public class UdpTypeServer { public static void main(String[] args) { System.out.println("接收方启动中..."); try { DatagramSocket server = new DatagramSocket(9999); byte[] container = new byte[1024*60]; DatagramPacket packet = new DatagramPacket(container,container.length); server.receive(packet); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packet.getData()); DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream); String msg = dataInputStream.readUTF(); int age = dataInputStream.readInt(); char ch = dataInputStream.readChar(); boolean flag = dataInputStream.readBoolean(); System.out.println("age="+age); System.out.println("msg="+msg); System.out.println("flag="+flag); System.out.println("ch="+ch); server.close(); dataInputStream.close(); byteArrayInputStream.close(); } catch (Exception e) { e.printStackTrace(); } } }
四. 聊天窗
服务端
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ZRY
* @version 1.0
*/
public class Server extends JFrame implements ActionListener, KeyListener {
/**
* 启动方法
* @param args
*/
public static void main(String[] args) throws Exception{
// UIManager.setLookAndFeel("org.jb2011.lnf.beautyeye.BeautyEyeLookAndFeelCross");
new Server();
}
private JScrollPane jScrollPane;//窗口,视图
private JTextField jTextField;//单行文本
private JPanel jPanel;//面板
private JTextArea jTextArea;//文本区域
private JButton jButton;//按钮
private BufferedWriter bufferedWriter=null;//输出流
public Server(){
myFrame(this);
figen();
}
/**
* Invoked when an action occurs.
*
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
JFprint();
}
/**
* Invoked when a key has been typed.
* See the class description for {@link KeyEvent} for a definition of
* a key typed event.
*
* @param e
*/
@Override
public void keyTyped(KeyEvent e) {
}
/**
* Invoked when a key has been pressed.
* See the class description for {@link KeyEvent} for a definition of
* a key pressed event.
*
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_ENTER){
JFprint();
}
}
/**
* Invoked when a key has been released.
* See the class description for {@link KeyEvent} for a definition of
* a key released event.
*
* @param e
*/
@Override
public void keyReleased(KeyEvent e) {
}
/**
* 在客户端的聊天窗新增内容
*/
public void JFprint(){
//获取输入框内容
String text = jTextField.getText();
text="服务端:\t"+text;
//System.lineSeparator() ===> \n\r
jTextArea.append(text+System.lineSeparator());
try {
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
//置空
jTextField.setText("");
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 发送内容给服务器
*/
public void figen(){
try {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line = null;
Date date=new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat();
// simpleDateFormat.format(date);
//在文本区域生成时间
jTextArea.append("\t"+ simpleDateFormat.format(date)+"\n");
while ((line=bufferedReader.readLine())!=null){
jTextArea.append(line+System.lineSeparator());
}
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 客户端窗口
* @param server
*/
public void myFrame(Server server){
//初始化面板
jPanel = new JPanel();
//初始化按钮
jButton=new JButton("发送");
//初始化输入框
jTextField = new JTextField(10);
//初始化文本区域
jTextArea =new JTextArea();
jTextArea.setEditable(false);
//初始化窗口
jScrollPane = new JScrollPane(jTextArea);
jPanel.add(jTextField);
jPanel.add(jButton);
//在当前对象的南面添加面板区域,包括输入框和按钮
server.add(jPanel, BorderLayout.SOUTH);
//在当前对象的中间添加文本区域
server.add(jScrollPane,BorderLayout.CENTER);
//初始化程序标题
server.setTitle("小同学");
//初始化大小
server.setSize(300,500);
//初始化位置
server.setLocation(500,300);
//使窗口位于屏幕中央
server.setLocationRelativeTo(null);
//
server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//显示
server.setVisible(true);
jButton.addActionListener(server);
jTextField.addKeyListener(server);
}
}
客户端
import javax.swing.*;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ZRY
* @version 1.0
*/
public class Client extends JFrame implements ActionListener, KeyListener {
private JScrollPane jScrollPane;//窗口,视图
private JTextField jTextField;//单行文本
private JPanel jPanel;//面板
private JTextArea jTextArea;//文本区域
private JButton jButton;//按钮
private BufferedWriter bufferedWriter=null;//输出流
public Client(){
myFrame(this);
figen();
}
/**
* 启动方法
* @param args
*/
public static void main(String[] args) throws Exception{
// UIManager.setLookAndFeel("org.jb2011.lnf.beautyeye.BeautyEyeLookAndFeelCross");
new Client();
}
/**
* Invoked when an action occurs.
*
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
JFprint();
figen();
}
/**
* Invoked when a key has been typed.
* See the class description for {@link KeyEvent} for a definition of
* a key typed event.
*
* @param e
*/
@Override
public void keyTyped(KeyEvent e) {
}
/**
* Invoked when a key has been pressed.
* See the class description for {@link KeyEvent} for a definition of
* a key pressed event.
*
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()== KeyEvent.VK_ENTER){
JFprint();
}
}
/**
* Invoked when a key has been released.
* See the class description for {@link KeyEvent} for a definition of
* a key released event.
*
* @param e
*/
@Override
public void keyReleased(KeyEvent e) {
}
/**
* 在客户端的聊天窗新增内容
*/
public void JFprint(){
//获取输入框内容
String text = jTextField.getText();
text="客户端:\t"+text;
//System.lineSeparator() ===> \n\r
jTextArea.append(text+System.lineSeparator());
try {
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
//置空
jTextField.setText("");
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 发送内容给服务器
*/
public void figen(){
try {
Socket socket=new Socket("localhost",8888);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line = null;
Date date=new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat();
// simpleDateFormat.format(date);
//在文本区域生成时间
jTextArea.append("\t"+ simpleDateFormat.format(date)+"\n");
while ((line=bufferedReader.readLine())!=null){
jTextArea.append(line+System.lineSeparator());
}
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 客户端窗口
* @param client
*/
public void myFrame(Client client){
//初始化面板
jPanel = new JPanel();
//初始化按钮
jButton=new JButton("发送");
//初始化输入框
jTextField = new JTextField(10);
//初始化文本区域
jTextArea =new JTextArea();
jTextArea.setEditable(false);
//初始化窗口
jScrollPane = new JScrollPane(jTextArea);
jPanel.add(jTextField);
jPanel.add(jButton);
//在当前对象的南面添加面板区域,包括输入框和按钮
client.add(jPanel, BorderLayout.SOUTH);
//在当前对象的中间添加文本区域
client.add(jScrollPane,BorderLayout.CENTER);
//初始化程序标题
client.setTitle("小同学");
//初始化大小
client.setSize(300,500);
//初始化位置
client.setLocation(500,300);
//使窗口位于屏幕中央
client.setLocationRelativeTo(null);
//
client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//显示
client.setVisible(true);
jButton.addActionListener(client);
jTextField.addKeyListener(client);
}
}