网络编程

网络编程学习

TCP与UDP协议

  • UDPUDPUser Datagram Protocol的简称,中文名为用户数据报协议。它是一种面向无连接的传输协议,何为面向无连接,就是在传输数据的时候,不需要判断是否与服务器建立连接就可以发送数据,双方是否连接成功并不知情。这样导致在传输的时候安全性较差,无法保证数据是否正确抵达,但在传输数据的效率上会稍微快一些。
  • TCPTCPTransmission Control Protocol,中文名为传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。何为面向连接,就是在传输数据之前,客户端需要与服务器建立连接,连接成功后才能传输数据进而实现通信目的,TCP建立连接遵循三次握手协议,即客户端向服务器发起SYN请求(第一次握手),服务器收到SYN请求并向客户端回应一个ACK+SYN给客户端(第二次握手),客户端接收到服务器的SYN报文并回应一个ACK(第三次握手)连接成功,这是可以开始传输数据。相比于UDP协议,TCP协议安全可靠,效率上稍微慢一点点。

    网络编程与网页编程

  • 网络编程:TCP/UDP,涉及的是底层东西。关注底层传输层技术。
  • 网页编程:jsp/servlet,涉及的是应用。关注的是上层的应用。
  • 网络编程可以写服务器,网页编程是在服务器基础上写应用。

    B/S 与 C/S

  • C/S是建立在局域网上的,B/S是建立在广域网上的.
  • C/S开发既要关注客户端也要关注服务器,B/S只需要关注客户端或服务器中的一端即可。
  • C/S一般用于建立在专用的网络上,小范围里的网络环境。 B/S一般用于建立在广域网上,不必是专门的网络硬件环境。

    基本概念

  • 网络通信和协议
    • 资源共享
    • 信息传输与集中处理
    • 负载均衡与分布处理
  • 通信协议
    • 计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。
  • 通信接口
    • 为了使两个结点之间能进行对话,必须在它们之间建立通信工具(即接口),使彼此之间能进行信息交换。接口包括两个部分:
      • 硬件装置:实现结点之间的信息传递。
      • 软件装置:规定双方进行通信的约定协议。
  • 网络分层
    • 由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成分,再将它们复合起来。最常用的复合方式是层次方式,即同层之间可以通信,上一层可以调用下一层,而与再下一层不发生关系。
      • 应用层
      • 表示层
      • 会话层
      • 传输层
      • 网络层
      • 数据链路层
      • 物理层
    • OSI参考模式:开放系统互连参考模型(Open System Interconnect
    • TCP/IP是一个协议族,也是按照层次划分,应用层(应用层、表现层、会话层)(SMTP/HTTP/DNS)、传输层(TCP/UDP)、互联网络层(IP/APP)、网络接口层(物理+数据链路层)。
    • TCP/IP参考模型:传输控制/网际协议 Transfer Controln Protocol/Internet Protocol
  • 数据封装
    • 应用层:准备数据
    • 传输层:接受应用层数据再添加上TCP的控制信息(称为TCP的头部),这个数据单元称为段。加入控制信息的过程称为封装,由此,将段交给网络层。
    • 网络层,接收到段,再添加上IP头部,这个数据单元称为包,然后将数据交给网络链路层。
    • 网络链路层:接收包并在包上在添加MAC头部和尾部,这个数据单元称为帧,然后,将数据交给物理层。
    • 物理层:接收帧后再将其转化为比特流,然后再网络上传输。
    • 发送方处理数据的方式是从高层到底层,逐层进行封装。
  • 数据拆封
    • 从底层到高层,到每一层时去掉该层的数据封装时所添加的头部即可。
    • 接收方数据处理方式从底层到高层,逐层进行数据解封。

      常用类操作

  • IP:是用于定位网络结点的。
    • InetAddress
  • Port:端口是用于区分软件的,是一个虚拟的概念。
    • 端口的表示是一个16位的二进制整数,2个字节,对应的二进制是0-65535
    • 查看所有端口:netstat -ano
    • 查看指定端口:netstat -anl | findstr "808"
    • 查看指定进程:tasklist | findstr "808"
    • 查看具体程序:使用任务管理器查看PID
    • 80端口:http协议
    • 8080端口:tomcat服务器
    • 1521端口:Oracle
    • 3306端口:mysql
    • InetSocketAddress:包含端口,用于Socket通信。
      • InetSocketAddress socketAddress=new InetSocketAddress("127.0.0.1",8080);
      • InetSocketAddress socketAddress=new InetSocketAddress("localhost",8080);
  • URL
    • URIUniversal Resource Identifier,统一资源标志符,用来标识抽象或物理资源的一个紧凑字符串。
    • URLUniversal Resource Locator,统一资源定位符,一种定位资源的主要访问机制的字符串,一个标准的URL必须包括:protocolhostportpathparameteranchor
    • URNUniversal Resource Name,统一资源名称,通过特定命名空间的唯一名称ID来标识资源。
    • www上,每一信息资源都有统一且唯一的地址,即统一资源定位符Uniform Resource Locator,如http://www.google.com:80/index.html。由4个部分组成:
      • 协议
      • 存放资源的主机域名
      • 端口号
      • 资源文件名
    • 网络三大基石:HTMLURLHTTP
  • 网络爬虫原理
    • 获取URL
    • 下载资源
    • 分析
    • 处理

      传输协议

  • TCP:smtp,ftp,http
  • UDP:SNMP,DNs
  • 传输层与应用层打交道:采用Socket套接字
  • SOCKET编程
    • UDP:通信双方不需要建立连接,通信双方完全平等
    • TCP:通信双方需要建立连接,连接建立时双方存在内在主次之分

      UDP编程

  • UDP基本步骤:
    • 发送端:
      • 创建DatagramSocket对象,并指定端口
      • 准备数据,一定要转成字节数组类型
      • 把数据封装成DatagramPacket包裹,需要指定目的地
      • 使用send()方法发送数据
      • 释放资源
    • 接收端:
      • 创建DatagramSocket对象,并指定接收端口
      • 准备容器 封装成DatagramPacket 包裹
      • 调用receive()方法接收数据,该方法是属于阻塞式的接收
      • 分析和处理数据
      • 释放资源
  • 所涉及到的类:
    • DatagramSocket:用于发送和接收数据包的套接字。
    • DatagramPacket:数据包

      TCP编程

  • TCP基本步骤
    • 创建服务器端
      • 指定端口 使用ServerSocket创建服务器。
      • 阻塞式等待连接 accept
      • 操作:输入输出流操作
      • 释放资源
    • 创建客户端
      • 建立连接:使用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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//服务端
package zhuchuli.chat05;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

/***
* 在线聊天室:服务端
* 目标:实现私聊
* @author aaa
*
*/
public class TMultiChat {
//用来存储客户端
private static CopyOnWriteArrayList<Channel> all=new CopyOnWriteArrayList<Channel>();
public static void main(String[] args) throws Exception {
System.out.println("-------Server-----");
//1.创建ServerSocket对象,并指定端口
ServerSocket server=new ServerSocket(8888);
//2.阻塞式接收
while(true) {
Socket client=server.accept();
System.out.println("一个客户端建立了连接");
Channel c=new Channel(client);
all.add(c);//管理所有的成员
new Thread(c).start();
}
}
//加入多线程
static class Channel implements Runnable{
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name;
//构造器
public Channel(Socket client) {
this.client=client;
try {
dis=new DataInputStream(client.getInputStream());
dos=new DataOutputStream(client.getOutputStream());
isRunning = true;
this.name=receive();
send("欢迎你回来");
sendOthers(this.name+"来到了本聊天室",true);
}catch(Exception e) {
//如果出现异常,则释放资源
System.out.println("创建对象时出异常");
release();
}
}
//接收消息
private String receive() {
String msg="";
try {
msg=dis.readUTF();
} catch (IOException e) {
//如果出现异常,则释放资源
System.out.println("接收数据时出现异常");
release();
}
return msg;
}
//群聊:获取自己的消息 发给其他人
//实现私聊
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate= msg.startsWith("@");
if(isPrivate) {//私聊的实现
int idx=msg.indexOf(":");
//获取目标和数据
String targetName=msg.substring(1,idx);
msg=msg.substring(idx+1);
for(Channel other:all) {
if(other.name.equals(targetName)) {//目标
other.send(this.name+"悄悄对你说:"+msg);
break;
}
}
}else { //群聊的实现
for(Channel other:all) {
if(other == this) { //自己
continue;
}
if(!isSys) {//群聊消息
other.send(this.name+"对所有人说:"+msg);
}else {
other.send(msg);
}

}
}
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//如果出现异常,则释放资源
System.out.println("写出数据时出现异常");
release();
}
}
//释放资源
private void release() {
this.isRunning=false;
ZhuchuliUtils.close(dis,dos,client);
//推出
all.remove(this);
sendOthers(this.name+"离开了本聊天室",true);
}
//线程体
@Override
public void run() {
while(isRunning) {
String msg=receive();
if(!msg.equals("")) {
//send(msg);//自己发送给自己
sendOthers(msg,false);
}
}
}
}
}
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
//客户端
package zhuchuli.chat05;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
/***3
* 客户端:在线聊天室
* 目标:实现私聊
*
* @author aaa
*
*/
public class TMultiClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----------Client----------");
//1.创建Socket对象,并于Server端建立连接
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入你的用户名:");
String name=br.readLine();
Socket client=new Socket("localhost",8888);

//2.输入输出操作:客户端发送消息
new Thread(new Send(client,name)).start();
new Thread(new Receive(client)).start();

}
}
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//相应的方法
package zhuchuli.chat05;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/***
* 使用多线程封装 发送端
* 1.发送消息
* 2.从控制台获取消息
* 3.释放资源
* 4.重写run方法
* @author aaa
*
*/
public class Send implements Runnable{

private BufferedReader console;
private DataOutputStream dos;
private Socket client;
private boolean isRunning=true;
private String name;
public Send(Socket client,String name) {
this.client=client;
console=new BufferedReader(new InputStreamReader(System.in));
this.name=name;
try {
dos=new DataOutputStream(client.getOutputStream());
send(name);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Send初始化时出现异常");
this.release();
}
}
//获取控制台输入的信息
private String getStrFromConsole() {

try {
return console.readLine();
} catch (IOException e) {
System.out.println("控制台输入时出现异常");
this.release();
}
return "";
}
//send方法发送
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println("发送消息时出现异常");
this.release();
}
}
@Override
public void run() {
while(isRunning) {
String msg=getStrFromConsole();
if(!msg.equals("")) {
send(msg);
}
}

}

//释放资源
private void release() {
this.isRunning=false;
ZhuchuliUtils.close(dos,client);
}

}
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
package zhuchuli.chat05;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/***
* 使用多线程封装 接收端
*1.接收消息
* 2.释放资源
* 3.重写run方法
* @author aaa
*
*/
public class Receive implements Runnable{
private DataInputStream dis;
private Socket client;
private boolean isRunning=true;
public Receive(Socket client) {
try {
dis=new DataInputStream(client.getInputStream());
} catch (IOException e) {
System.out.println("Receive初始化时出现异常");
this.release();
}
}
//接收消息
private String receive() {
String msg="";
try {
msg=dis.readUTF();
} catch (IOException e) {
System.out.println("接收消息时出现异常");
this.release();
}
return msg;
}
@Override
public void run() {
while(isRunning){
String msg=receive();
if(!msg.equals("")) {
System.out.println(msg);
}
}
}

//释放资源
private void release() {
this.isRunning=false;
ZhuchuliUtils.close(dis,client);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package zhuchuli.chat05;

import java.io.Closeable;

/***
* 工具类
* @author 朱楚利
*
*/
public class ZhuchuliUtils {
public static void close(Closeable ...targets) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
e.printStackTrace();
}

}
}
}

感谢上海尚学堂老师的教学视频!!!!