当前位置:   article > 正文

Java中的TCP编程与UDP编程简介_java tcp udp

java tcp udp

网络编程的常用协议

        IP协议是个分组交换协议,它不保证可靠传输。而TCP协议 是传输控制协议,它是面向连接 的协议,支持可靠传输建立协议之上的,简单地说,IP协议只负责发数据包,不保证顺序和正确性,而TCP协议负责控制数据包传输,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过 接收确认 、 超时重传 这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。   

        TCP协议也是应用最广泛的协议,许多高级协议都是建立在TCP协议之上的,例如HTTPSMTP等。
        UDP协议(User Datagram Protocol)是一种数据报文协议,它是无连接协议,不保证可靠传输。因为UDP协议在通信前不需要建立连接,因此它的传输效率比TCP高,而且UDP协议,TCP 协议要简单得多。选择UDP协议时,传输的数据通常是能容忍丢失的,例如,一些语音视频通信的应用会选择UDP 协议。

什么是Socket?

        我们要了解什么是TCP编程与UDP编程,首先我们需要先了解什么是Socket。

        Socket是一个抽象的概念,一个应用程序通过Socket建立一个远程连接,而Socket内部通过TCP/IP协议把数据传送至网络。

        Socket就是套接字,由IP地址和端口号(范围是0~65535)组成,端口号是由操作系统随机分配的,它是一个0~65535之间的一个数字。小于1024的端口号是特权端口,一般都是需要管理员权限,但是大于1024的端口号可以被任意用户的应用程序打开。通过端口号,Socket才能正确连接本机中的应用程序。

        当使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收。

        因此,当Socket 连接成功地在服务器端和客户端之间建立后:

        对服务器端来说,它的Socket是指定的IP地址和指定的端口号。

        对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

TCP编程 (实现人机对话)

服务器端

        首先我们先将需要和人机对话的内容存入一个Map集合用来存储问题与回答,当客户端发出问题时,如果有则返回相对应的值,如果没有,则返回null。

  1. Map<String, String> chatMap = new HashMap<String, String>(){
  2. {
  3. put("你好", "你好呀");
  4. put("hi", "hi~");
  5. put("hello", "哈喽");
  6. put("吃了吗", "没呢,你呢");
  7. put("孤勇者", "爱你孤身走暗巷");
  8. put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
  9. put("很高兴认识你", "我也是哦");
  10. }
  11. };

        然后,我们创建一个Socket对象,在服务器端通过Java通过的ServerSocket创建,传入一个监听端口,通过一个死循环使得服务器一直处于监听状态,使用accept()方法接收来自客户端的连接。接着创建一个输入流,并调用getInputStream()方法,获取来自客户端提出的问题。再创建一个输出流,将问题的回答反馈给客户端。

具体代码实现如下:

  1. public class ChatServer {
  2. public static void main(String[] args) {
  3. Map<String, String> chatMap = new HashMap<String, String>(){
  4. {
  5. put("你好", "你好呀");
  6. put("hi", "hi~");
  7. put("hello", "哈喽");
  8. put("吃了吗", "没呢,你呢");
  9. put("孤勇者", "爱你孤身走暗巷");
  10. put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
  11. put("很高兴认识你", "我也是哦");
  12. }
  13. };
  14. try(ServerSocket server = new ServerSocket(9966)){
  15. while(true) {
  16. // 发生客户端连接
  17. Socket client = server.accept();
  18. // 获取该客户端的IP地址
  19. String clientIP = client.getInetAddress().getHostAddress();
  20. try(BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
  21. BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
  22. // 获取该客户端的提问
  23. String question = reader.readLine();
  24. System.out.println("【服务器】 来自客户端" + clientIP + "提问:" + question);
  25. // 获取该问题的答案
  26. String answer = chatMap.get(question);
  27. answer = answer == null ? "我不知道你在说什么!" : answer;
  28. // 发送答案至客户端
  29. writer.write(answer);
  30. writer.flush();
  31. }
  32. }
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

        我们可以用一个简单的三元运算符来判定如果返回值为null时,可以输出指定的内容。

客户端

        客户端相比于服务器端比较简单。

        首先创建Socket对象,并传入服务器端的IP地址和端口号,通过Scanner获取来自用户提出的问题。然后创建输出流,通过getOutputStream()将问题传输给服务器端,再创建输入流用来获取来自服务器端的回答。

  1. public class CharClient {
  2. public static void main(String[] args) {
  3. Scanner input = new Scanner(System.in);
  4. while(true) {
  5. // 创建Socket,连接服务器
  6. try (Socket client = new Socket("192.168.254.153", 9966);
  7. BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
  8. BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
  9. ){
  10. // 获取控制台的输入(问题)
  11. String question = input.nextLine();
  12. if(question.equals("over")) {
  13. break; // 结束循环
  14. }
  15. // 发送问题至服务器
  16. writer.write(question);
  17. writer.flush();
  18. // 暂时结束本次输出
  19. client.shutdownOutput();
  20. // 获取来自服务器的“答案”
  21. String answer = reader.readLine();
  22. System.out.println("【客户端】 来自服务器的回答:" + answer);
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. System.out.println("本次问答结束!");
  28. }
  29. }

运行结果显示:

 UDP编程(简单的双人对话实现)

        相对于TCP来说,UDP就简单很多,UDP不需要建立连接,也没有通过数据流传送,而是通过一个一个的数据包来实现。

        UDP也是需要使用Socket来监听端口的的,不过它使用的是java提供的DatagramSocket。

发送端

        发送数据时:通过setData()方法,将要发送的内容转换成字符串存储到定义的空数组中,再调用send()方法,实现数据的发送。

        接收数据时:通过receive()方法,将接收到的内容传入之前receivePacket包定义的空数组,通过DatagramPacket返回的getData()、getOffset()和getLength()获取数据,并转成字符串,实现数据的接收。

  1. public class ChatB {
  2. public static void main(String[] args) {
  3. Scanner input = new Scanner(System.in);
  4. // 客户端B监听7788端口
  5. try (DatagramSocket socket = new DatagramSocket(7788)){
  6. // 提前创建两个Packet数据包,分别用于发送和接收
  7. DatagramPacket sendPacket = new DatagramPacket(
  8. new byte[1024], 1024, // 数据
  9. new InetSocketAddress("192.168.1.5", 8899) // 目的地
  10. );
  11. DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
  12. while(true) {
  13. // 发送
  14. System.out.print("我说:");
  15. String sendContent = input.nextLine();
  16. sendPacket.setData(sendContent.getBytes());
  17. socket.send(sendPacket);
  18. if(sendContent.equals("over")) {
  19. System.out.println("你退出聊天!!!");
  20. return;
  21. }
  22. // 接收
  23. socket.receive(receivePacket);
  24. String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
  25. if(receiveContent.equals("over")) {
  26. System.out.println("对方已退出聊天!!!");
  27. break;
  28. }
  29. System.out.println("她说:" + receiveContent);
  30. }
  31. } catch (SocketException e) {
  32. e.printStackTrace();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

接收端

        发送端与接收端思路整体一致,只不过接收端是先收再发。

  1. public class ChatA {
  2. public static void main(String[] args) {
  3. Scanner input = new Scanner(System.in);
  4. //客户端B监听8899端口
  5. try (DatagramSocket socket = new DatagramSocket(8899)){
  6. // 提前创建两个Packet数据包,分别用于发送和接收
  7. DatagramPacket sendPacket = new DatagramPacket(
  8. new byte[1024], 1024, // 数据
  9. new InetSocketAddress("192.168.1.5", 7788) // 目的地
  10. );
  11. DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
  12. while(true) {
  13. // 接收
  14. socket.receive(receivePacket);
  15. String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
  16. if(receiveContent.equals("over")) {
  17. System.out.println("对方已退出聊天!!!");
  18. break;
  19. }
  20. System.out.println("她说:" + receiveContent);
  21. // 发送
  22. System.out.print("我说:");
  23. String sendContent = input.nextLine();
  24. sendPacket.setData(sendContent.getBytes());
  25. socket.send(sendPacket);
  26. if(sendContent.equals("over")) {
  27. System.out.println("你退出聊天!!!");
  28. return;
  29. }
  30. }
  31. } catch (SocketException e) {
  32. e.printStackTrace();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

运行结果显示:

 

 实现多人对话

        基于双人对话的基础,在进行整改。

        将组内成员的IP和姓名可以存入一个Map集合,在输出的时候调用,可以西安市这句话是哪位成员说的。再创建一个List集合,存入对应人数的DatagramPacket对象。选出一位管理员作为发送端,其他成员作为接收端。每个人固定自己的端口号进行监听,在发送信息时,通过for()循环遍历输出,向每位成员发送。

管理员(发送端)

  1. public class Work {
  2. public static void main(String[] args) {
  3. Scanner input = new Scanner(System.in);
  4. Map<String, String> map = new HashMap<String, String>(){
  5. {
  6. put("/192.168.254.153", "**");
  7. put("/192.168.254.181", "**");
  8. put("/192.168.254.150", "**");
  9. put("/192.168.254.163", "**");
  10. }
  11. };
  12. List<DatagramPacket> list1 = new ArrayList<DatagramPacket>();
  13. try (DatagramSocket socket = new DatagramSocket(5555)){
  14. // 发送
  15. DatagramPacket sendPacket1 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.153", 9999));
  16. DatagramPacket sendPacket2 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.181", 8888));
  17. DatagramPacket sendPacket3 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.150", 7777));
  18. DatagramPacket sendPacket4 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.163", 6666));
  19. list1.add(sendPacket1);
  20. list1.add(sendPacket2);
  21. list1.add(sendPacket3);
  22. list1.add(sendPacket4);
  23. // 接收
  24. DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
  25. while(true) {
  26. // 发送
  27. System.out.print("我说:");
  28. String sendContent = input.nextLine();
  29. for(int i = 0; i < list1.size(); i++) {
  30. list1.get(i).setData(sendContent.getBytes());
  31. socket.send(list1.get(i));
  32. }
  33. // 接收
  34. socket.receive(receivePacket);
  35. String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
  36. String ip = receivePacket.getAddress().toString();
  37. if(receiveContent.equals("over")) {
  38. System.out.println(map.get(ip) + "已退出聊天!!!");
  39. break;
  40. }
  41. System.out.println(map.get(ip) + "说:" + receiveContent);
  42. }
  43. } catch (SocketException e) {
  44. e.printStackTrace();
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }

组内成员(接收端)

  1. public class Work {
  2. public static void main(String[] args) {
  3. Scanner input = new Scanner(System.in);
  4. Map<String, String> map = new HashMap<String, String>(){
  5. {
  6. put("/192.168.254.153", "**");
  7. put("/192.168.254.181", "**");
  8. put("/192.168.254.150", "**");
  9. put("/192.168.254.188", "**");
  10. }
  11. };
  12. List<DatagramPacket> list1 = new ArrayList<DatagramPacket>();
  13. try (DatagramSocket socket = new DatagramSocket(5555)){
  14. // 发送
  15. DatagramPacket sendPacket1 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.153", 9999));
  16. DatagramPacket sendPacket2 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.181", 8888));
  17. DatagramPacket sendPacket3 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.150", 7777));
  18. DatagramPacket sendPacket4 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.188", 5555));
  19. list1.add(sendPacket1);
  20. list1.add(sendPacket2);
  21. list1.add(sendPacket3);
  22. list1.add(sendPacket4);
  23. // 接收
  24. DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
  25. while(true) {
  26. // 接收
  27. socket.receive(receivePacket);
  28. String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
  29. String ip = receivePacket.getAddress().toString();
  30. if(receiveContent.equals("over")) {
  31. System.out.println(map.get(ip) + "已退出聊天!!!");
  32. break;
  33. }
  34. System.out.println(map.get(ip) + "说:" + receiveContent);
  35. }
  36. // 发送
  37. System.out.print("我说:");
  38. String sendContent = input.nextLine();
  39. for(int i = 0; i < list1.size(); i++) {
  40. list1.get(i).setData(sendContent.getBytes());
  41. socket.send(list1.get(i));
  42. }
  43. } catch (SocketException e) {
  44. e.printStackTrace();
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号