当前位置:   article > 正文

Java 基于 TCP 的 Socket 编程_java socket编程之tcp编程

java socket编程之tcp编程

目录

1、什么是TCP协议?

2、什么是Socket(套接字)?

3、简单的TCP网络编程实现

4、一个服务端支持多个客户端连接的实现


1、什么是TCP协议

        TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,用于在计算机网络中传输数据。它是互联网协议套件(TCP/IP)中的核心协议之一。

        TCP协议提供了一种可靠的、有序的、面向字节流的数据传输机制,它能够确保数据的完整性、可靠性和顺序性。TCP协议在应用层之上建立了一种端到端的通信,通过使用IP协议进行数据包的传输。

        TCP协议的特点和功能包括:

  1. 可靠性:TCP协议通过使用序列号、确认和重传等机制,确保数据的可靠传输。接收端会确认已接收的数据,并请求重新传输丢失或损坏的数据。
  2. 有序性:TCP协议会保持发送数据的顺序,并确保接收端按照正确的顺序重组数据。这样应用程序可以按照发送顺序处理数据,而不必担心数据包乱序到达。
  3. 流量控制:TCP协议使用滑动窗口机制来控制数据的发送速率,确保发送方和接收方之间的数据流平衡,避免数据包的丢失或拥塞。
  4. 拥塞控制:TCP协议通过使用拥塞窗口和拥塞避免算法来控制数据的发送速率,并避免网络拥塞的发生。它会根据网络的拥塞情况动态调整发送速率。
  5. 面向连接:TCP协议是一种面向连接的协议,使用三次握手来建立连接,四次握手来关闭连接。在数据传输之前,发送端和接收端需要建立一个可靠的连接。

        由于TCP协议具有可靠性和有序性,以及对拥塞的控制能力,它被广泛用于可靠数据传输的应用中,如网页浏览、文件传输、电子邮件、远程登录和数据通信等。

2、什么是Socket(套接字)?

        Socket(套接字)是计算机网络编程中用于实现网络通信的一种编程接口或抽象概念。它提供了一种标准的接口,使应用程序能够通过网络与其他计算机进行通信

        Socket可以看作是应用程序与网络之间的一个通信端点,类似于电话中的插座。通过Socket,应用程序可以创建、连接、发送和接收数据,以实现网络通信。

        Socket通常使用TCP/IP协议栈作为底层网络协议,但也可以与其他协议一起使用,如UDP(User Datagram Protocol)和ICMP(Internet Control Message Protocol)等。

        在网络编程中,通常需要以下几个步骤来使用Socket:

  1. 创建Socket:应用程序通过调用系统提供的Socket函数来创建一个新的Socket实例。创建Socket时需要指定网络协议、传输方式和地址族等参数。
  2. 绑定Socket:创建Socket后,应用程序需要将其绑定到一个特定的IP地址和端口号。绑定操作将Socket与特定的网络地址关联起来,以便其他计算机可以通过该地址与之通信。
  3. 连接Socket:如果应用程序是作为客户端与远程服务器进行通信,它需要通过调用连接函数来与目标服务器建立连接。连接操作会建立客户端与服务器之间的网络连接通道。
  4. 发送和接收数据:已经建立连接的Socket可以使用发送和接收函数来进行数据的发送和接收。应用程序可以通过Socket发送数据到远程主机,或者接收来自远程主机的数据。
  5. 关闭Socket:当通信结束或不再需要时,应用程序可以调用关闭函数来关闭Socket连接,并释放相关资源。

        通过Socket编程接口,开发人员可以轻松实现网络通信功能,包括客户端和服务器之间的数据交换、网络服务的实现、远程操作和网络应用的开发等。Socket提供了一种灵活而强大的机制,使得网络通信变得简单而高效。

3、简单的TCP网络编程实现

        在明白TCP协议和Socket概念的前提下,想要实现用Java程序来进行TCP编程其实不难,首先再重复一下编程中的相关概念:

  • IP:唯一的标识 Internet 上的某台计算机,在 Java 程序中通过 InetAddress 类获取 IP
  • 端口号:可以理解为计算机上运行的进程的入口,不同的进程有不同的端口号
  • Socket:一个应用程序通过一个 Socket 来建立一个远程连接,而 Socket 内部通过 TCP/IP 协议把数据传输到网络,Socket 是两个进程之间网络通信的桥梁

        接下来,创建两个程序,一个充当服务器端,另一个充当客户端;服务器端会主动监听某个指定的端口,客户端必须主动连接服务器的 IP 地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个 TCP 连接,双方后续就可以随时发送和接收数据。

        服务端程序的实现:

  1. import java.net.*;
  2. import java.io.*;
  3. public class TcpServer {
  4. public static void main(String[] args) {
  5. try {
  6. ServerSocket ss = new ServerSocket(8001); // 驻守在8001端口
  7. Socket s = ss.accept(); // 阻塞,等到有客户端连接上来
  8. System.out.println("welcome to the java world");
  9. InputStream ips = s.getInputStream(); // 有client连上来,打开输入流
  10. OutputStream ops = s.getOutputStream(); // 打开输出流
  11. // 同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
  12. ops.write("Hello, Client!".getBytes()); // 输出一句话给客户端
  13. BufferedReader br = new BufferedReader(new InputStreamReader(ips));
  14. // 从客户端读取一句话
  15. System.out.println("Client said: " + br.readLine());
  16. ips.close();
  17. ops.close();
  18. s.close();
  19. ss.close();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

        客户端程序的实现:

  1. import java.io.BufferedReader;
  2. import java.io.DataOutputStream;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStream;
  6. import java.net.InetAddress;
  7. import java.net.Socket;
  8. public class TcpClient {
  9. public static void main(String[] args) {
  10. try {
  11. Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); //需要服务端先开启
  12. // 同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
  13. InputStream ips = s.getInputStream(); //开启通道的输入流
  14. BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
  15. OutputStream ops = s.getOutputStream(); //开启通道的输出流
  16. DataOutputStream dos = new DataOutputStream(ops);
  17. BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));
  18. while (true) {
  19. String strWord = brKey.readLine();
  20. if (strWord.equalsIgnoreCase("quit")) {
  21. break;
  22. } else {
  23. System.out.println("I want to send: " + strWord);
  24. // 向服务端发送数据(使用输出流)
  25. dos.writeBytes(strWord + System.getProperty("line.separator"));
  26. // 打印接收到的数据(使用输入流)
  27. System.out.println("Server said: " + brNet.readLine());
  28. }
  29. }
  30. dos.close();
  31. brNet.close();
  32. brKey.close();
  33. s.close();
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }

        分别启动服务端和客户端程序,演示效果如下:

        注意:服务端需要先于客户端启动,否则客户端因连接不到指定的进程而报错。同时输入输出流还可以传各种类型的数据,详情请参考 Java 的各种 I/O 流实现。

4、一个服务端支持多个客户端连接的实现

        实际场景中,一个服务端往往可以支持多个客户端的连接,为多个客户端提供服务。如下图所示:

        此处,为了实现上述想法,可以通过多线程改进一下服务端程序的实现:

  1. import java.net.*;
  2. public class TcpServer2 {
  3. public static void main(String[] args) {
  4. try {
  5. ServerSocket serverSocket = new ServerSocket(8001);
  6. while (true) {
  7. Socket socket = serverSocket.accept();
  8. System.out.println("监听到 client 连接...");
  9. // 启动一个线程
  10. new Thread(new Worker(socket)).start();
  11. }
  12. //ss.close();
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. }

        Worker.class 类的详情如下:

  1. import java.net.*;
  2. import java.io.*;
  3. class Worker implements Runnable {
  4. Socket socket;
  5. public Worker(Socket socket) {
  6. this.socket = socket;
  7. }
  8. public void run() {
  9. try {
  10. System.out.println("Worker 已经启动...");
  11. InputStream ips = socket.getInputStream();
  12. OutputStream ops = socket.getOutputStream();
  13. BufferedReader br = new BufferedReader(new InputStreamReader(ips));
  14. DataOutputStream dos = new DataOutputStream(ops);
  15. while (true) {
  16. String strWord = br.readLine();
  17. System.out.println("client said:" + strWord + ":" + strWord.length());
  18. if (strWord.equalsIgnoreCase("quit")){
  19. break;
  20. }
  21. String strEcho = strWord + " 666";
  22. // dos.writeBytes(strWord +"---->"+ strEcho +"\r\n");
  23. System.out.println("server said:" + strWord + "---->" + strEcho);
  24. dos.writeBytes(strWord + "---->" + strEcho + System.getProperty("line.separator"));
  25. }
  26. br.close();
  27. // 关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()
  28. dos.close();
  29. socket.close();
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }

        分别启动服务端和客户端1和2后的演示效果如下:

        在客户端1,输入Hi:

        在客户端2,输入Hello:

        服务端的输出如下:

        至此,Java 基于 TCP 的 Socket 编程结束。有关 Java 基于 UDP 的 Socket 编程,可以参考我的这篇文章:《Java 基于 UDP 的 Socket 编程》。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/704300
推荐阅读
相关标签
  

闽ICP备14008679号