网络编程
计算机网络
把不同区域的计算机,通过通信设备和网线,使计算机通过软件实现资源共享和信息传递
Java提供的网络类库,将实现细节隐藏起来.
网络编程的目的:
直接或间接地通过网络协议与其它计算机进行通讯。
网络通信要素:
如何精确到找到计算机网络中某台主机 IP(计算机)/端口号(电脑上的软件)
如何传输数据 网络通信协议
IP/端口
IP(计算机)/端口号(电脑上的软件)
网络通信协议
计算机网络中实现通信必须有一些约定,即通信协议.
例如:代码结构(传输内容),传输的速度,出错控制…
TCP是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。
TCP三次握手过程
第一次握手:主机A通过向主机B 发送一个含有同步序列号的标志位的数据段给主机B,向主机B 请求建立连接,
通过这个数据段, 主机A告诉主机B 两件事:我想要和你通信;你可以用哪个序列号作为起始数据段来回应我。
第二次握手:主机B 收到主机A的请求后,用一个带有确认应答(ACK)和同步序列号(SYN)标志位的数据段响应主机A,
也告诉主机A两件事:我已经收到你的请求了,你可以传输数据了;你要用那个序列号作为起始数据段来回应我
第三次握手:主机A收到这个数据段后,再发送一个确认应答,确认已收到主机B 的数据段:
"我已收到回复,我现在要开始传输实际数据了,这样3次握手就完成了,主机A和主机B 就可以传输数据了。
TCP四次挥手过程
第一次: 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求 ;
第二次: 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1;
第三次: 由B 端再提出反方向的关闭请求,将FIN置1 ;
第四次: 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束.。
特点
1.面向连接 每次通信前建立连接
2.仅支持单播传输
3.面向字节流
4.可靠传输 数据量大 效率低
5.提供拥塞控制
6.TCP提供全双工通信
UDP
- 面向无连接
首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。
并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作 - 有单播,多播,广播的功能
UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,
也就是说 UDP 提供了单播,多播,广播的功能。 - UDP是面向报文的
发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,
既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文 - 不可靠性
首先不可靠性体现在无连接上,通信都不需要建立连接,
想发就发,这样的情况肯定不可靠。 - 头部开销小,传输数据报文时是很高效的。
java中TCP协议通信实现
Socket 网络套接字 表示客户端 ,里面封装服务器IP,端口
ServerSocet 表示服务器端,监听客户端的连接
单个客户端与服务器端互相发送消息
服务器端
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket= null;
try {
serverSocket = new ServerSocket(9999);
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("等待客户端连接");
Socket socket = serverSocket.accept();
System.out.println("客户端连接成功");
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
while (true) {
String ms = in.readUTF();
System.out.println("客户端说:" + ms);
if (ms.equals("886")) {
break;
}
System.out.println("服务器端输入");
String str = sc.next();
out.writeUTF(str);
}
in.close();
out.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败");
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Socket socket= null;
try {
socket = new Socket("localhost",9999);
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器连接失败");
}
try {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("客户端输入:");
String ms = sc.next();//阻塞式的
out.writeUTF(ms);
if (ms.equals("886")) {
break;
}
String str = in.readUTF();
System.out.println("服务器端说:" + str);
}
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("读写失败");
}
}
}