
网络编程基础
计算机网络
- 多台计算机通过通讯线路相连接
互联网
将所有计算机网络相连接
协议
- TCP
- IP
IP地址
标识一个网络接口
一台接入互联网的计算机至少有一个IP地址
我感觉应该是一块无线网卡对应一个ip地址
分类
按格式
IPV4
- 32位整数
- 耗尽
IPV6
按范围
- 公网
- 内网(局域网)
网络号
获得
- ip地址经过子网掩码过滤
用途
网络号相同
- 设备在同一个网络下,可以直接通信
网络号不同
- 设备不在一个网络下,要依靠路由器或交换机通信
网络设备
网关
- 路由器
- 交换机
路由
- 通过网关把一个网络的数据包发送到另一个网络
域名
为什么存在?
因为IP地址太难记
也就是说 域名就是给ip地址起个小名儿 叫起来方便
特殊的localhost
因为特殊所以特殊
我看了C盘windows下的那个hosts文件,就像是字典一样,一个ip地址对应一个域名,我怀疑域名解析就是靠这个实现的。
- 127.0.0.1
网络模型
分层
原因
- 因为复杂所以分层
目的
- 简化网络操作
有哪些层呢
应用层
- 提供应用程序之间的通信
传输层
- 提供端到端的传输
IP层
- 根据目标地址选择路由传输数据
网络接口层
- 处理数据然后通过物理设备(网线\wifi)传输
协议
作用
- 交易之前总得商量好吧
常用协议
IP协议
负责发数据包
好像是瞎jb‘发的 据说不保证顺序 正确与否
也不知道是不是真的
TCP协议
负责控制数据包传输
负责的协议,通过一些手段(目前我还听不懂的名词)保证可靠、正确、稳定。
- 建立连接
- 传输数据
- 断开连接
UDP
VS TCP
UDP完任务型选手
我只管传输数据,有没有人接受我不care
无连接
速度更快
协议更简单
质量更垃圾
数据必丢失
应用
能容忍数据丢失的场合
据说音视频通话比较常用,我想也是,能听来或者看来个百分之八九十就可了。
TCP编程
socket
据说socket、tcp和部分ip的功能是由操作系统实现并提供的,不同的语言只是对操作系统提供的接口进行了一些包装
啥是socket
- application通过socket在网络间传输数据
- socket通过TCP/IP协议在网络间传输数据
为啥需要socket
ip地址是网卡的标识
说的粗糙一点就是 设备的标识
ip地址过于粗糙
socket精确到application
socket长啥样啊
- ip地址再加点儿料(端口)
端口
为啥需要端口啊
ip地址标识网络接口,if我的电脑有一个网卡,这个网卡有一个ip地址,我的电脑上运行了好多需要联网的应用,比如qq、战网、steam,还有很多其他应用。我的网卡对于从远方发过来的包照单全收,但这些包都是名花有主的,因为物质资料还没有到极大丰富的地步,所以不能实行共产主义平均分配或者每人来一份,我们得按需分配,按闹分配,比如qq你只能领取属于自己的包,那怎么实现这样的需求呢?
咱这样,你们每个应用,给自己整一个端口,比如战网,你的port是988,那我网卡以后就通过这个端口跟你keep touch,其他应用都要有自己的端口,俺网卡按照包的标识,按照咱约定好的端口,按需分配,这样就解决问题了。- 因为socket
特权端口
比如我的应用是用一个普通user打开的,那这个应用就不能使用1024以下的端口
- 1024以下需要管理员权限
socket编程
服务器端
服务客户端的端
服务端会监听某个端口
从端口获得数据包然后服务客户端(我猜的
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64package Laboratory;
import javax.xml.crypto.Data;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class Experiment {
public static void main(String[] args) throws IOException {
//服务器端,可能会有很多客户端请求与我共舞
//监听指定的端口,可以指定ip地址,ip地址标识网络接口,如果不指定ip地址,表明监听计算机上的所有网络接口
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("server is running");
//处理和客户端之间的连接
while (true) {
//ServerSocket的accept方法,如果有客户端请求连接,我就整个socket对象给他,如果没有人请求连接,这个方法就会block
Socket socket = serverSocket.accept();
System.out.println("Connected from " + socket.getRemoteSocketAddress());
Thread thread = new Handler(socket);
thread.start();
}
}
}
class Handler extends Thread {
Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
public void run() {
try (InputStream inputStream = this.socket.getInputStream()) {
try (OutputStream outputStream = this.socket.getOutputStream()) {
handle(inputStream, outputStream);
}
} catch (Exception e) {
try {
this.socket.close();
} catch (IOException ioe) {
}
System.out.println("Client disconnected");
}
}
private void handle(InputStream inputStream, OutputStream outputStream) throws IOException {
var writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
writer.write("Fku\n");
writer.flush();
while (true) {
String s = reader.readLine();
if (s.equals("bye")) {
writer.write("bye too");
writer.flush();
break;
}
writer.write("fku 3000 times " + s);
writer.flush();
}
}
}
1
2
客户端
主动连接服务器的ip和指定端口
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package Laboratory;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class Experiment {
public static void main(String[] args) throws IOException {
//客户端的TCP程序
//连接指定的服务器和端口,如果连接成功,会返回一个socket实例,用于日后的通信
Socket socket = new Socket("localhost", 6666);
try (InputStream inputStream = socket.getInputStream()) {
try (OutputStream outputStream = socket.getOutputStream()) {
handle(inputStream, outputStream);
}
}
socket.close();
System.out.println("Disconnected");
}
private static void handle(InputStream inputStream, OutputStream outputStream) throws IOException {
var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
var writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
Scanner scanner = new Scanner(System.in);
System.out.println("[server] " + reader.readLine());
while (true) {
System.out.print(">>> "); //打印提示
String s = scanner.nextLine(); //读取一行输入
writer.write(s);
writer.newLine();
writer.flush();
String str = reader.readLine();
System.out.println("<<<" + str);
if (str.equals("bye")) {
break;
}
}
}
}
编程使得客户端和服务端进行通信
三次握手
tcp是要和服务器建立连接的啊
- 屌丝:可以吗?
- 女神:可以,你想什么时候?
- 屌丝:今ここだ
UDP编程
UDP VS TCP
UDP不需要建立连接
当然也就不需要断开连接
UDP没有流的概念
两者的端口相互独立
就是 假如有两个应用,一个用UDP,一个用TCP,就算两个用一个端口也没事儿
服务器端
监听指定的端口
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package Laboratory;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class Experiment {
public static void main(String[] args) throws IOException {
//服务端的操作:准备一个datagramSocket对象,利用他的receive和send方法接收和发送数据
//服务器端首先使用如下语句在指定的端口监听UDP数据包:
DatagramSocket datagramSocket = new DatagramSocket(6666);
while (true) {
//准备一个byte[]类型的缓冲包用来接收来自端口的数据
byte[] buffer = new byte[1024];
//通过DatagramPacket对象的方法receive接收数据包
DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(datagramPacket);
//通过DatagramPacket的getOffset和getLength方法确定接收到的数据在缓冲区的起始位置
String s = new String(datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength(), StandardCharsets.UTF_8);
byte[] data = "ACK".getBytes(StandardCharsets.UTF_8);
datagramPacket.setData(data);
datagramSocket.send(datagramPacket);
}
}
}
客户端
操作
- 向服务器发送UDP包
- 接收服务器返回的UDP包
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package Laboratory;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class Experiment {
public static void main(String[] args) throws IOException {
//客户端
//客户端创建DatagramSocket的时候不需要指定端口,分配端口这个活儿是OS干的,所以说OS是程序员的好朋友
DatagramSocket datagramSocket = new DatagramSocket();
//此处有别于服务器端,服务器端可以循环到天荒地老,但客户端有所不同,需要设置最长等待时间,过期不候
datagramSocket.setSoTimeout(1000);
//UDP不需要建立连接,没错,这里的connect并不是真连接,而是想把服务器的ip和端口保存下来,以便之后向服务器发送UDP数据包
datagramSocket.connect(InetAddress.getByName("localhost"), 6666);
//现在可以发送数据了
//先来点数据
byte[] data = "What's going on?".getBytes();
//和DatagramPacket绑在一起
DatagramPacket datagramPacket = new DatagramPacket(data, data.length);
//通过Socket的方法send将Packet发送到服务器,必须是先发再收,不然服务器不知道客户端的ip和端口号
datagramSocket.send(datagramPacket);
//发送之后就可以接受数据了
//接受数据,和服务端一样
//先准备一个byte数组用来接受数据
byte[] buffer = new byte[1024];
//把buffer和packet绑定起来
datagramPacket = new DatagramPacket(buffer, buffer.length);
//通过socket的receive方法接受数据存到预先设定的packet里
datagramSocket.receive(datagramPacket);
//转换成String
String str = new String(datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength());
//如果可以,可以选择断开连接
//既然不存在连接,当然也就不存在断开的对象,确实如此,此处的disconnect只是把socket对象恢复出厂设置,以便于socket可以再利用而已
datagramSocket.disconnect();
}
}
发送
传统的邮件
- 投递到邮局——邮局2——邮局3——信箱
电子邮件
- 从用户的邮箱软件发送到服务器——服务器2——服务器3——邮箱
邮箱软件
- MUA
- Mail User Agent
邮件服务器
MTA
MDA
- 邮件最终的归属
- 或许是某个服务器的某块硬盘
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class Mail {
public static void main(String[] args) throws MessagingException {
String smtp = "smtp.qq.com";
String username = "674602921@qq.com";
String password = "grzbslakcefkbceg";
Properties properties = new Properties();
properties.put("mail.smtp.host", smtp);
properties.put("mail.smtp.port", 465);
properties.put("mail.smtp.auth", "true");
properties.put("mail.starttls.enable", "true");
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
session.setDebug(true);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("674602921@qq.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("ljm158675@gmail.com"));
message.setSubject("Hey", "UTF-8");
message.setText("Java,please!");
Transport.send(message);
}
}
public class Mail {
public static void main(String[] args) throws MessagingException {
String smtp = "smtp.qq.com";
String username = "674602921@qq.com";
String password = "grzbslakcefkbceg";
Properties properties = new Properties();
properties.put("mail.smtp.host", smtp);
properties.put("mail.smtp.port", 465);
properties.put("mail.smtp.auth", "true");
properties.put("mail.starttls.enable", "true");
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
session.setDebug(true);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("674602921@qq.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("ljm158675@gmail.com"));
message.setSubject("Hey", "UTF-8");
message.setText("Java,please!");
Transport.send(message);
}
}
接收
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import com.sun.mail.pop3.POP3SSLStore;
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.util.Properties;
public class Mail {
public static void main(String[] args) throws MessagingException, IOException {
String host = "pop3.example.com";
String username = "bob@example.com";
String password = "********";
int port = 995;
Properties properties = new Properties();
properties.setProperty("mail.store.protocol", "pop3");
properties.setProperty("mail.pop3.host", host);
properties.setProperty("mail.pop3.port", String.valueOf(port));
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.socketFactory.port", String.valueOf(port));
URLName urlName = new URLName("pop3", host, port, "", username, password);
Session session = Session.getInstance(properties, null);
session.setDebug(true);
Store store = new POP3SSLStore(session, urlName);
store.connect();
// 获取收件箱:
Folder folder = store.getFolder("INBOX");
// 以读写方式打开:
folder.open(Folder.READ_WRITE);
// 打印邮件总数/新邮件数量/未读数量/已删除数量:
System.out.println("Total messages: " + folder.getMessageCount());
System.out.println("New messages: " + folder.getNewMessageCount());
System.out.println("Unread messages: " + folder.getUnreadMessageCount());
System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
// 获取每一封邮件:
Message[] messages = folder.getMessages();
for (Message message : messages) {
// 打印每一封邮件:
printMessage((MimeMessage) message);
}
}
static void printMessage(MimeMessage msg) throws IOException, MessagingException {
// 邮件主题:
System.out.println("Subject: " + MimeUtility.decodeText(msg.getSubject()));
// 发件人:
Address[] froms = msg.getFrom();
InternetAddress address = (InternetAddress) froms[0];
String personal = address.getPersonal();
String from = personal == null ? address.getAddress() : (MimeUtility.decodeText(personal) + " <" + address.getAddress() + ">");
System.out.println("From: " + from);
// 继续打印收件人:
}
}
HTTP编程
建立TCP连接
请求(HTTP,浏览器)
- HTTP HEADER
- HTTP BODY