Java进阶学习之网络编程(4)
《计算机网络》作为计算机专业的必修课,估计大家对他仍有后怕,这本书很厚,知识面很广,建议有时间的朋友通篇阅读和理解。
1.网络编程概述
1.1.目的
通过通信线路将多台计算机连接起来,并进行数据传输。
1.2.常用的网络协议
1.2.1.TCP
TCP(Transmission Control Protocol):传输控制协议,是一种面向连接、可靠的、基于字节流的传输层通讯协议。
TCP的三次握手:
SYN:同步序列编号Synchronize Sequence Numbers
ACK:确认字符Acknowledge character
- 第一次握手:A的TCP客户端首先创建传输控制块TCB,然后向B发送连接请求报文段(SYN=1,seq=x),A进入SYN-SENT状态;
- 第二次握手:B收到连接请求报文后,如同意建立连接,则向A发送确认(SYN=1,ACK=1,确认号ack=x+1,seq=y),B进入SYN-RCVD状态;
- 第三次握手:A收到B的确认后,向B发出确认报文(ACK=1,确认号ack=y+1,seq=x+1),A进入ESTABLISHED,B收到A的确认后也进入ESTABLISHED。
TCP四次挥手:
MSL:报文最大存活时间
- A向B发送连接释放报文段(FIN=1,seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1状态,等待B的确认;
- B收到后发出确认报文段(ACK=1,ack=u+1,seq=v),B进入CLOSE-WAIT状态,此时TCP连接处于半关闭状态,A到B的连接释放;
- A收到B的确认后,进入FIN-WAIT-2状态,等待B发出连接释放报文;
- B没有向A发出数据,B发出连接释放报文(FIN=1,ACK=1,seq=w,ack=u+1),B进入TIME-WAIT状态,等待A确认;
- A收到B的连接释放报文后,发出确认报文(ACK=1,seq=u+1,ack=w+1),A进入TIME-WAIT状态,此时TCP未释放掉,经过时间等待计数器设置的时间2MSL后,A进入CLOSED状态。
1.2.2.UDP
UDP(User Datagram Protocol):用户数据报协议,是一种无连接的传输协议。
特点:
- 不可靠的协议,不建立连接,不进行数据检查,不等待应答,导致可能会出现数据丢失等现象
- 报头很短,开销很小
- 有较好的实用性,传输效率很高,受软件性能、带宽、收发端主机性能限制
2.Socket网络编程
2.1.Socket是什么
套接字Socket就是双向通信中一端的抽象。
Socket由IP地址和端口port确认。
2.2.Socket工作流程
- 服务器开启监听
- 客户端请求连接
- 确认连接
2.3.案例
服务端编写:
public class MyServer extends Thread {
private ServerSocket serverSocket;
public MyServer(int port) throws IOException {
serverSocket = new ServerSocket(8888);
System.out.println("服务端已启动,监听端口:" + serverSocket.getLocalPort());
}
@Override
public void run() {
Socket server = null;
OutputStream os = null;
DataOutputStream dos = null;
while (true) {
try {
server = serverSocket.accept();
System.out.println(server.getRemoteSocketAddress() + "连接成功!");
os = server.getOutputStream();
dos = new DataOutputStream(os);
dos.writeUTF("hello!");
dos.flush();
dos.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try {
Thread t = new MyServer(8888);
t.run();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端编写:
public class MyClient {
public static void main(String[] args) {
Socket client = null;
InputStream is = null;
DataInputStream dis = null;
try {
client = new Socket("127.0.0.1", 8888);
is = client.getInputStream();
dis = new DataInputStream(is);
System.out.println(dis.readUTF());
dis.close();
is.close();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后按照Socket工作流程,先启动服务点监听,执行结果:
启动客户端进行连接,执行结果:
连接成功后,接收到服务端发来的字符串"hello!"
看一下服务端有什么变化:
由于服务端是个死循环对8888
端口进行监听,我们启动客户端多次看看服务端有什么变化: