Socket
Socket的定义
Socket套接字是网络通信的编程接口,而TCP是一种面向连接的、可靠的传输协议。在使用TCP进行网络通信时,应用程序可以使用Socket套接字来建立连接、发送和接收数据。Socket套接字是实现TCP协议的一种方式。
socket可以看作实现网络传输的对象
Socket套接字可以用于实现不同的网络协议,包括TCP、UDP等
使用java.net.Socket
创建了一个Socket
对象。Socket
类通常用于TCP、UDP通信。
Socket套接字是用于网络通信的编程接口,它提供了一种机制,使得应用程序能够通过网络进行数据传输。Socket套接字可以用于实现不同的网络协议,包括TCP、UDP等。 在使用TCP进行网络通信时,Socket套接字是实现TCP协议的一种方式。应用程序可以通过创建一个TCP Socket套接字来建立与远程服务器的连接。一旦连接建立,应用程序可以使用Socket套接字进行数据的发送和接收。数据通过Socket套接字从一个端点(例如客户端)发送到另一个端点(例如服务器)。
Socket的常用方法:
getInetAddress(); 远程服务端的IP地址
getPort(); 远程服务端的端口
getLocalAddress() 本地客户端的IP地址
getLocalPort() 本地客户端的端口
getInputStream(); 获得输入流
getOutStream(); 获得输出流
值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。
TCP
1、TCP的定义
TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议。它是基于IP,用于在网络中传输数据。TCP协议提供了可靠的、按顺序的、基于字节流的数据传输。它通过连接的建立、数据的分段和重组、确认和重传等机制,确保数据的可靠性和完整性。
TCP协议位于传输层,作用是提供可靠的字节流服务,为了准确无误地将数据送达目的地
全双工:通讯的双方可以同时发送和接收消息
2、TCP的三次握手
谓三次握手即建立TCP连接,为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。
标志位:
1、SYN:发送/同步标志,用来建立连接
2、ACK:用于确认收到数据,发送一个确认应答
3、FIN:用于关闭连接
- 第一步:
客户端发送一个SYN请求报文,端口状态变为SYN_SENT状态,
其中报文包含seq序列号,有发送端随机生成
- 第二步:
当服务器收到报文时候,发出应答,服务器的端口状态变为SYN_RECV状态,服务器回复客户端一个SYN和ACK报文
- 第三步:
当客户端接收到服务器报文以后,服务器向客户端发送ACK报文,与此同时客户端的端口状态变为ESTABLSHED状态。在服务器接收到客户端发送的报文后,服务器的端口状态变为ESTABLISHED状态
ESTABLISHED状态,表示连接成功。
3、TCP的四次挥手
- 第一步:
客户端向服务器发送一个带有FIN(Finish)标志的TCP报文段,表示自己已经完成数据的发送
- 第二步:
服务器收到连接释放报文,发送确认报文(ACK),表示已经收到关闭请求。
- 第三步:
服务端向客户端发送一个带有FIN标志的TCP报文段给关闭连接的一方,表示自己也完成了数据的发送。
- 第四步:
客户端收到服务端的连接释放报文后,发送一个确认报文段(ACK)作为响应,表示已经收到关闭请求。
这样,双方都发送了FIN和ACK,完成了连接的关闭。在四次挥手过程中,每一方都要发送一个FIN报文段,并等待对方的确认。这样可以确保双方都能正常关闭连接,并且保证数据的可靠传输。
总结起来:
1、服务端
1.1 服务端的读数据
public class serve{
public static void main(String[] args) throws IOException{
System.out.println("服务端启动");
//1、服务端监听的端口号:用于监听指定的端口
ServerSocket serverSocket=new ServerSocket(8888);
//2、接收客户端发送过来的socket
//accept是阻塞式的方法,直到有客户端连接才会往下执行
Socket socket=serverSocket.accept();
//3、读取客户端发过来的内容,通过socket获取输入流
InputStream in=socket.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(in);
//初始化一个空字符串变量“content”以存储从读取器读取的每一行内容。
String content="";
while((content=reader.readLine())!=null){
System.out.println(content);
}
//关闭输入流
socket.shutdownInput();
reader.close();
socket.close();
serverSocket.close();
}
}
1.2 服务端的写
//向客户端发消息
OutputStreamWriter writer=new OutputStreamWriter(socket.getOutputStream());
writer.write("发送给客户端的消息");
writer.flush();
socket.shutdownOutput();
2、客户端
2.1 客户端的写
public class Client{
public static void main(String[] args)throws IOException{
System.out.println("启动客户端");
//1、创建客户端的socket,
//a、服务端的IP地址 b、服务端监听的端口号
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
OutputStreamWriter writer=new OutputStreamWriter(os)
writer.writer("这是发送给服务器的");
//上下文刷新
writer.flush();
socket.shutdownOutput();
socket.close();
}
}
2.2 客户端的读
//客户端接收消息
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String content="";
while ((content=reader.readLine())!=null){
System.out.println(content);
}
socket.shutdownInput();
//关闭连接
socket.close();
3、服务端和客户端的相互发消息代码
3.1 服务端
package org.example;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
Socket:套接字,是对协议的实现,网络通讯时,都是套接字进行数据传递
TCP:Transmission Control Protocol,传输控制协议
客户端和服务端
全双工:通讯的双方可以同时发送和接收消息
*/
public class Server {
//服务端
public static void main(String[] args) throws IOException {
System.out.println("服务端启动");
//1、服务端监听的端口号
//用于监听指定的端口
ServerSocket serverSocket=new ServerSocket(8888);
//2、接收客户端发送过来的socket
//accept是阻塞式的方法,直到有客户端连接才会往下执行
Socket socket=serverSocket.accept();
//可以获取客户端的IP地址
System.out.println(socket.getInetAddress());
System.out.println(socket.getPort());
//3、读取客户端发送过来的内容 通过socket获取输入流
InputStream in=socket.getInputStream();
// Reader reader1=new InputStreamReader(in);
// BufferedReader reader=new BufferedReader(reader1);
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
String content;
while((content=reader.readLine())!=null){
System.out.println(content);
}
//关闭输入流
socket.shutdownInput();
//向客户端发送消息
OutputStreamWriter writer=new OutputStreamWriter(socket.getOutputStream());
writer.write("发送给客户端的消息");
writer.flush();
socket.shutdownOutput();
//4、可选 关闭连接,关闭服务端
reader.close();
socket.close();
serverSocket.close();
}
}
3.2 客户端
package org.example;
import java.io.*;
import java.net.Socket;
public class Client {
//客户端
public static void main(String[] args) throws IOException {
System.out.println("客户端启动");
/*1、创建客户端 socket,
*服务端的IP地址
*服务端监听的端口号
*/
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
OutputStreamWriter writer=new OutputStreamWriter(os);
writer.write("这是发送给服务端的消息");
// writer.write("aaaaaaa");
writer.flush();
//输出已经完成 调用了shutdownOutput方法或者close,服务端才能接收消息
socket.shutdownOutput();
//接收消息
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String content="";
while ((content=reader.readLine())!=null){
System.out.println(content);
}
socket.shutdownInput();
//关闭连接
socket.close();
}
}
UDP
UDP是无连接的协议,因此在发送数据之前不需要建立连接。每个数据包都是独立的,可能会丢失、重复或乱序。因此,使用UDP时需要注意数据的可靠性和顺序性。
DatagramSocket是Java编程语言中用于实现UDP(User Datagram Protocol)通信的类。它提供了在网络上发送和接收UDP数据包的功能。
1、发送方
package org.example;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.sql.SQLOutput;
public class UDP {
public static void main(String[] args) throws IOException {
//创建Socket 参数为当前socket监听的端口号
DatagramSocket socket=new DatagramSocket(6666);
//创建数据包
byte[] content="发送的数据".getBytes();
DatagramPacket packet=new DatagramPacket(content,
0,
content.length,
InetAddress.getByName("127.0.0.1"),
7777);
/*
1、要发送的内容(字节数组)
2、数组下标的偏移量(从数组的哪个下标开始截取)
3、要发送内容的长度
4、目的地的IP地址
5、目的地的端口号
*/
//发送数据包
socket.send(packet);
System.out.println("发送完成");
//关闭socket
socket.close();
}
}
2、接收方
package org.example;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Arrays;
public class UDPRecive {
public static void main(String[] args) throws IOException {
DatagramSocket socket=new DatagramSocket(7777);
byte[] bytes=new byte[1024];
DatagramPacket packet=new DatagramPacket(bytes,bytes.length);
//接收消息
socket.receive(packet);
//获取发送方的信息
//发送方的IP地址
InetAddress inetAddress=packet.getAddress();
System.out.println(inetAddress);
//发送方监听的端口号
int port=packet.getPort();
System.out.println(port);
//内容的长度
int len=packet.getLength();
System.out.println(len);
//获取内容
byte[] data=packet.getData();
// System.out.println(Arrays.toString(data));
String content=new String(data,0,len);
System.out.println(content);
//关闭socket
socket.close();
}
}
TCP和UDP的区别
TCP和UDP是两种常见的传输层协议,在网络通信中扮演着不同的角色和具有不同的特点。 主要区别如下:
- 连接性:TCP是面向连接的协议,而UDP是无连接的协议。TCP在通信之前需要建立连接,而UDP不需要建立连接,可以直接发送数据。
- 可靠性:TCP提供可靠的数据传输,确保数据的完整性和顺序性。它使用确认、重传和流量控制等机制来保证数据的可靠性。UDP则不保证可靠性,它不提供确认、重传和流量控制等机制,数据可能会丢失、重复或乱序。
- 速度和效率:由于TCP提供了可靠性保证,它在数据传输方面相对较慢,因为它需要处理确认和重传等机制。UDP由于不需要这些机制,因此传输速度更快,效率更高。
- 数据量和分段:TCP可以处理大量数据,并将数据分段传输。它将数据分成较小的数据块(段),并根据网络的情况进行传输。UDP没有数据分段的概念,它将整个数据包作为一个单独的单元进行传输。
- 应用场景:TCP通常用于需要可靠性和顺序性的应用,如文件传输、电子邮件、网页浏览等。UDP通常用于实时应用,如音频/视频流传输、在线游戏等,对于实时性要求较高且可以容忍一些数据丢失的场景。 总结起来,TCP是面向连接、可靠的、适合大数据量和需要顺序传输的场景。UDP是无连接、不可靠的、适合实时性要求高且可以容忍数据丢失的场景。
TCP | UDP | |
---|---|---|
面向连接 | 无连接 | |
可靠传输,使用流量控制和拥塞控制 | 不可靠传输 | |
有序,TCP会重新排序 | 无序 | |
传输速度慢 | 传输速度快 | |
一对一 | 支持多交互通信 | |
面向字节流 | 面向报文 |
报文就是一组客户端和服务端都认可的信息数据