Socket/TCP/UDP
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("发送完成");//关闭socketsocket.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);//关闭socketsocket.close();}
}
TCP和UDP的区别
TCP和UDP是两种常见的传输层协议,在网络通信中扮演着不同的角色和具有不同的特点。 主要区别如下:
- 连接性:TCP是面向连接的协议,而UDP是无连接的协议。TCP在通信之前需要建立连接,而UDP不需要建立连接,可以直接发送数据。
- 可靠性:TCP提供可靠的数据传输,确保数据的完整性和顺序性。它使用确认、重传和流量控制等机制来保证数据的可靠性。UDP则不保证可靠性,它不提供确认、重传和流量控制等机制,数据可能会丢失、重复或乱序。
- 速度和效率:由于TCP提供了可靠性保证,它在数据传输方面相对较慢,因为它需要处理确认和重传等机制。UDP由于不需要这些机制,因此传输速度更快,效率更高。
- 数据量和分段:TCP可以处理大量数据,并将数据分段传输。它将数据分成较小的数据块(段),并根据网络的情况进行传输。UDP没有数据分段的概念,它将整个数据包作为一个单独的单元进行传输。
- 应用场景:TCP通常用于需要可靠性和顺序性的应用,如文件传输、电子邮件、网页浏览等。UDP通常用于实时应用,如音频/视频流传输、在线游戏等,对于实时性要求较高且可以容忍一些数据丢失的场景。 总结起来,TCP是面向连接、可靠的、适合大数据量和需要顺序传输的场景。UDP是无连接、不可靠的、适合实时性要求高且可以容忍数据丢失的场景。
TCP | UDP | |
---|---|---|
面向连接 | 无连接 | |
可靠传输,使用流量控制和拥塞控制 | 不可靠传输 | |
有序,TCP会重新排序 | 无序 | |
传输速度慢 | 传输速度快 | |
一对一 | 支持多交互通信 | |
面向字节流 | 面向报文 |
报文就是一组客户端和服务端都认可的信息数据