基本概念
网络:一组相互连接的计算机
– 多台计算机组成
– 使用物理线路进行连接
- 网络编程的三要素
【1】IP地址:唯一标识网络上的每一台计算机
两台计算机之间通信的必备要素
【2】端口号:计算机中应用的标号(代表一个应用程序)
0-1024系统使用或保留端口 ,有效端口0-65536
【3】通信协议:通信的规则
TCP,UDP
网络分层
IP地址
端口:port
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。
数据封装拆分
网络爬虫原理
TCP编程
相当于打电话,需要建立连接
效率相对比较低,数据传输安全
三次握手完成(点名->答到->确认)
UDP编程
相当于收短信(有字数限制),不需要建立连接
数据报的大小限制在64k内
效率较高,不安全,容易丢包
Socket套接字
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
Java中使用Socket完成TCP程序的开发,使用此类可以方便的建立可靠的、双向的、持续性的、点对点的通讯连接
在Socket的程序开发中,服务器端使用ServerSocket等待客户端的连接,对于java的网络程序来讲,每一个客户端都使用一个Socket对象表示
- 基于TCP协议的Socket编程
获取网络地址
package com.petrel;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author Petrel
* @data 2020/6/30 18:26
*/
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost); //运行结果:DESKTOP-GNC7NCU/192.168.1.*** 主机名/IP地址
InetAddress inetAdd = InetAddress.getByName("DESKTOP-GNC7NCU");
System.out.println(inetAdd);//运行结果:DESKTOP-GNC7NCU/192.168.1.***
InetAddress inetAdd2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAdd2);//运行结果:www.baidu.com/112.80.248.76
System.out.println(inetAdd2.getHostAddress());//运行结果:112.80.248.76
System.out.println(inetAdd2.getHostName());//运行结果:www.baidu.com
}
}
客户端向服务端发送数据
package com.petrel.client;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:00
*/
//客户端向服务端发送数据
public class Client {
public static void main(String[] args) throws IOException {
//创建socket对象,其实是开启实现io的虚拟接口(此接口不是java中的接口,而是类似于网线的插槽)
//需要指定数据接受方的ip地址和端口号
Socket client = new Socket("localhost",10086);
//获取输出流对象,想服务端发送数据
OutputStream outputStream = client.getOutputStream();
//将输出流对象进行包装
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
//传输数据
dataOutputStream.writeUTF("miffy");
//关闭流操作
dataOutputStream.close();
outputStream.close();
client.close();
}
}
------------
package com.petrel.server;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:07
*/
//客户端和服务端先启用服务端
public class Server {
public static void main(String[] args) throws IOException {
//服务端需要使用serversocket来开放本地的端口
ServerSocket serverSocket = new ServerSocket(10086);
//需要接受client传输过来的数据,需要定义socket对象
Socket server = serverSocket.accept();
//通过server获取输入流对象
InputStream inputStream = server.getInputStream();
//对输入流做包装,包装成DataInputStream
DataInputStream dataInputStream = new DataInputStream(inputStream);
//读取对应的数据
String str = dataInputStream.readUTF();
System.out.println(str);
//关闭所有的流操作
dataInputStream.close();
inputStream.close();
server.close();
serverSocket.close();
}
}
客户端向服务端发送和接收数据
package com.petrel.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:11
*/
public class Client2 {
public static void main(String[] args) throws IOException {
//创建客户端的套接字
Socket client = new Socket("127.0.0.1",10000);
//--------------------向外进行输出---------------
//获取输出流对象
OutputStream outputStream = client.getOutputStream();
//数据输出
outputStream.write("hello java".getBytes());
//--------------------接受服务端返回的消息---------------------------
//获取输出流对象
InputStream inputStream = client.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("服务端的响应数据是:" + new String(buf,0,length));
//关闭流操作
inputStream.close();
outputStream.close();
client.close();
}
}
------------
package com.petrel.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:14
*/
public class Server2 {
public static void main(String[] args) throws IOException {
//创建serversocket对象
ServerSocket serverSocket = new ServerSocket(10000);
//获取服务端的套接字对象
Socket server = serverSocket.accept();
//--------------------接受客户端的输入---------------------------
//获取输入流对象
InputStream inputStream = server.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("客户端传输的数据是:" + new String(buf,0,length));
//---------------------返回客户端数据----------------------------------
OutputStream outputStream = server.getOutputStream();
outputStream.write("你好,收到".getBytes());
//关闭流
outputStream.close();
inputStream.close();
server.close();
serverSocket.close();
}
}
传输图片
package com.petrel.client;
import java.io.*;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:25
*/
public class PicClient {
public static void main(String[] args) throws IOException {
//创建图片的输入流对象
FileInputStream fileInputStream = new FileInputStream("img.jpg");
//创建Socket
Socket client = new Socket("localhost",10086);
//获取输出流对象
OutputStream outputStream = client.getOutputStream();
int temp = 0;
while ((temp = fileInputStream.read())!=-1){
outputStream.write(temp);
}
client.shutdownOutput();//关流
//接受服务端的响应
InputStream inputStream = client.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println(new String(buf,0,length));
client.shutdownInput();//关流
//关闭操作
inputStream.close();
outputStream.close();
fileInputStream.close();
client.close();
}
}
------------
package com.petrel.server;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/6/30 22:25
*/
public class PicServer {
public static void main(String[] args) throws IOException {
//创建服务端对象,开放端口
ServerSocket serverSocket = new ServerSocket(10086);
//创建服务端的socket
Socket server = serverSocket.accept();
//获取输入流对象
InputStream inputStream = server.getInputStream();
//创建文件输出流对象
FileOutputStream fileOutputStream = new FileOutputStream("miffy.jpg");
int temp = 0;
while ((temp = inputStream.read())!=-1){
fileOutputStream.write(temp);
}
server.shutdownInput();//关流
//添加流输出完成的标志
//上传图片结束之后给予客户端响应
OutputStream outputStream = server.getOutputStream();
outputStream.write("上传成功".getBytes());
server.shutdownOutput();//关流
//关闭操作
outputStream.close();
fileOutputStream.close();
inputStream.close();
server.close();
serverSocket.close();
System.out.println("启动成功");
}
}
登录
package com.petrel.client;
import java.io.Serializable;
/**
* @author Petrel
* @data 2020/7/1 9:56
*/
public class User implements Serializable {
private static final long serialVersionUID = 1280401151637226935L; //序列化接口 可以通过User快捷方式建立
private String username;
private String password;
public User(){
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
------------
package com.petrel.client;
import com.petrel.client.User;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author Petrel
* @data 2020/7/1 10:02
*/
public class LoginClient {
public static void main(String[] args) throws IOException {
Socket client = new Socket("localhost",10000);
OutputStream outputStream = client.getOutputStream();
//完成登录功能,需要传输一个user对象
User user = getUser();
//传输对象需要ObjectOutputStream
ObjectOutputStream objectOutputStream =new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(user);
//调用shutdown方法告诉对方传输完成
client.shutdownOutput();
//接受响应
DataInputStream dataInputStream = new DataInputStream(client.getInputStream());
String str = dataInputStream.readUTF();
System.out.println(str);
//关闭流操作
dataInputStream.close();
objectOutputStream.close();
outputStream.close();
}
public static User getUser(){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
return new User(username,password);
}
}
------------
package com.petrel.server;
import com.petrel.client.User;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/7/1 10:30
*/
public class LoginServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(10000);
Socket server = serverSocket.accept();
//获取输入流对象
InputStream inputStream = server.getInputStream();
//需要使用ObjectInputStream对象
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
User user = (User) objectInputStream.readObject();
String str = "";
if ("miffy".equals(user.getUsername())&&"miffy".equals(user.getPassword())){
System.out.println("欢迎你"+user.getUsername());
str = "登录成功";
}else {
str = "登录失败";
}
//截断输入流
server.shutdownInput();
//给客户端响应
DataOutputStream outputStream = new DataOutputStream(server.getOutputStream());
outputStream.writeUTF(str);
//关闭流操作
server.shutdownOutput();
inputStream.close();
server.close();
serverSocket.close();
System.out.println("已启动");
}
}
------------
package com.petrel.server;
import com.petrel.client.User;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/7/1 10:30
*/
public class LoginServer2 {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(10000);
while (true){
Socket socket = serverSocket.accept();
LoginThread loginThread = new LoginThread(socket);
new Thread(loginThread).start();
}
//serverSocket.close();
}
}
------------
package com.petrel.server;
import com.petrel.client.User;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
/**
* @author Petrel
* @data 2020/7/1 12:00
*/
public class LoginThread implements Runnable{
private Socket socket;
public LoginThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
ObjectInputStream objectInputStream = null;
DataOutputStream dataOutputStream = null;
try {
objectInputStream = new ObjectInputStream(socket.getInputStream());
User user = (User) objectInputStream.readObject();
String str = "";
if("msb".equals(user.getUsername()) && "msb".equals(user.getPassword())){
System.out.println("欢迎你:"+user.getUsername());
str = "登录成功";
}else{
str="登录失败";
}
socket.shutdownInput();
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(str);
socket.shutdownOutput();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
dataOutputStream.close();
objectInputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP
package com.petrel.client;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* @author: 马士兵教育
* @create: 2019-10-13 16:05
*/
public class UDPClient {
public static void main(String[] args) throws Exception {
//创建udp通信的socket
DatagramSocket datagramSocket = new DatagramSocket(10000);
//从控制台读取数据
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.getBytes().length, InetAddress.getByName("localhost"),10001);
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
------------
package com.petrel.server;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* @author: 马士兵教育
* @create: 2019-10-13 16:10
*/
//UDP服务端和客户端都要定义端口
//server和client想先启动那个都可以
public class UDPServer {
public static void main(String[] args) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket(10001);
byte[] buf = new byte[1024];
//用来接受传输过来的数据
DatagramPacket datagramPacket = new DatagramPacket(buf,buf.length);
//利用创建好的数据报包对象来接受数据
datagramSocket.receive(datagramPacket);
//打印输出信息
System.out.println( new String(datagramPacket.getData(),0,datagramPacket.getLength()));
datagramSocket.close();
}
}