赞
踩
IP协议是个分组交换协议,它不保证可靠传输。而TCP协议 是传输控制协议,它是面向连接 的协议,支持可靠传输建立协议之上的,简单地说,IP协议只负责发数据包,不保证顺序和正确性,而TCP协议负责控制数据包传输,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过 接收确认 、 超时重传 这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。
TCP协议也是应用最广泛的协议,许多高级协议都是建立在TCP协议之上的,例如HTTPSMTP等。
UDP协议(User Datagram Protocol)是一种数据报文协议,它是无连接协议,不保证可靠传输。因为UDP协议在通信前不需要建立连接,因此它的传输效率比TCP高,而且UDP协议,TCP 协议要简单得多。选择UDP协议时,传输的数据通常是能容忍丢失的,例如,一些语音视频通信的应用会选择UDP 协议。
我们要了解什么是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地址和一个由操作系统分配的随机端口号。
首先我们先将需要和人机对话的内容存入一个Map集合用来存储问题与回答,当客户端发出问题时,如果有则返回相对应的值,如果没有,则返回null。
- Map<String, String> chatMap = new HashMap<String, String>(){
- {
- put("你好", "你好呀");
- put("hi", "hi~");
- put("hello", "哈喽");
- put("吃了吗", "没呢,你呢");
- put("孤勇者", "爱你孤身走暗巷");
- put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
- put("很高兴认识你", "我也是哦");
- }
- };
然后,我们创建一个Socket对象,在服务器端通过Java通过的ServerSocket创建,传入一个监听端口,通过一个死循环使得服务器一直处于监听状态,使用accept()方法接收来自客户端的连接。接着创建一个输入流,并调用getInputStream()方法,获取来自客户端提出的问题。再创建一个输出流,将问题的回答反馈给客户端。
具体代码实现如下:
- public class ChatServer {
- public static void main(String[] args) {
- Map<String, String> chatMap = new HashMap<String, String>(){
- {
- put("你好", "你好呀");
- put("hi", "hi~");
- put("hello", "哈喽");
- put("吃了吗", "没呢,你呢");
- put("孤勇者", "爱你孤身走暗巷");
- put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
- put("很高兴认识你", "我也是哦");
- }
- };
-
- try(ServerSocket server = new ServerSocket(9966)){
-
- while(true) {
- // 发生客户端连接
- Socket client = server.accept();
-
- // 获取该客户端的IP地址
- String clientIP = client.getInetAddress().getHostAddress();
-
- try(BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
-
- // 获取该客户端的提问
- String question = reader.readLine();
- System.out.println("【服务器】 来自客户端" + clientIP + "提问:" + question);
-
- // 获取该问题的答案
- String answer = chatMap.get(question);
- answer = answer == null ? "我不知道你在说什么!" : answer;
-
- // 发送答案至客户端
- writer.write(answer);
- writer.flush();
- }
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
我们可以用一个简单的三元运算符来判定如果返回值为null时,可以输出指定的内容。
客户端相比于服务器端比较简单。
首先创建Socket对象,并传入服务器端的IP地址和端口号,通过Scanner获取来自用户提出的问题。然后创建输出流,通过getOutputStream()将问题传输给服务器端,再创建输入流用来获取来自服务器端的回答。
- public class CharClient {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
-
- while(true) {
- // 创建Socket,连接服务器
- try (Socket client = new Socket("192.168.254.153", 9966);
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
- BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
- ){
- // 获取控制台的输入(问题)
- String question = input.nextLine();
- if(question.equals("over")) {
- break; // 结束循环
- }
-
- // 发送问题至服务器
- writer.write(question);
- writer.flush();
-
- // 暂时结束本次输出
- client.shutdownOutput();
-
- // 获取来自服务器的“答案”
- String answer = reader.readLine();
- System.out.println("【客户端】 来自服务器的回答:" + answer);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- System.out.println("本次问答结束!");
- }
- }
运行结果显示:
相对于TCP来说,UDP就简单很多,UDP不需要建立连接,也没有通过数据流传送,而是通过一个一个的数据包来实现。
UDP也是需要使用Socket来监听端口的的,不过它使用的是java提供的DatagramSocket。
发送数据时:通过setData()方法,将要发送的内容转换成字符串存储到定义的空数组中,再调用send()方法,实现数据的发送。
接收数据时:通过receive()方法,将接收到的内容传入之前receivePacket包定义的空数组,通过DatagramPacket返回的getData()、getOffset()和getLength()获取数据,并转成字符串,实现数据的接收。
- public class ChatB {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
-
- // 客户端B监听7788端口
- try (DatagramSocket socket = new DatagramSocket(7788)){
-
- // 提前创建两个Packet数据包,分别用于发送和接收
- DatagramPacket sendPacket = new DatagramPacket(
- new byte[1024], 1024, // 数据
- new InetSocketAddress("192.168.1.5", 8899) // 目的地
- );
- DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
-
- while(true) {
- // 发送
- System.out.print("我说:");
- String sendContent = input.nextLine();
-
- sendPacket.setData(sendContent.getBytes());
- socket.send(sendPacket);
-
- if(sendContent.equals("over")) {
- System.out.println("你退出聊天!!!");
- return;
- }
-
- // 接收
- socket.receive(receivePacket);
- String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
- if(receiveContent.equals("over")) {
- System.out.println("对方已退出聊天!!!");
- break;
- }
- System.out.println("她说:" + receiveContent);
- }
-
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
发送端与接收端思路整体一致,只不过接收端是先收再发。
- public class ChatA {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
-
- //客户端B监听8899端口
- try (DatagramSocket socket = new DatagramSocket(8899)){
-
- // 提前创建两个Packet数据包,分别用于发送和接收
- DatagramPacket sendPacket = new DatagramPacket(
- new byte[1024], 1024, // 数据
- new InetSocketAddress("192.168.1.5", 7788) // 目的地
- );
- DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
-
- while(true) {
- // 接收
- socket.receive(receivePacket);
- String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
- if(receiveContent.equals("over")) {
- System.out.println("对方已退出聊天!!!");
- break;
- }
- System.out.println("她说:" + receiveContent);
-
- // 发送
- System.out.print("我说:");
- String sendContent = input.nextLine();
- sendPacket.setData(sendContent.getBytes());
- socket.send(sendPacket);
- if(sendContent.equals("over")) {
- System.out.println("你退出聊天!!!");
- return;
- }
- }
-
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
运行结果显示:
基于双人对话的基础,在进行整改。
将组内成员的IP和姓名可以存入一个Map集合,在输出的时候调用,可以西安市这句话是哪位成员说的。再创建一个List集合,存入对应人数的DatagramPacket对象。选出一位管理员作为发送端,其他成员作为接收端。每个人固定自己的端口号进行监听,在发送信息时,通过for()循环遍历输出,向每位成员发送。
- public class Work {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
-
- Map<String, String> map = new HashMap<String, String>(){
- {
- put("/192.168.254.153", "**");
- put("/192.168.254.181", "**");
- put("/192.168.254.150", "**");
- put("/192.168.254.163", "**");
- }
- };
-
- List<DatagramPacket> list1 = new ArrayList<DatagramPacket>();
- try (DatagramSocket socket = new DatagramSocket(5555)){
-
- // 发送
- DatagramPacket sendPacket1 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.153", 9999));
- DatagramPacket sendPacket2 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.181", 8888));
- DatagramPacket sendPacket3 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.150", 7777));
- DatagramPacket sendPacket4 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.163", 6666));
- list1.add(sendPacket1);
- list1.add(sendPacket2);
- list1.add(sendPacket3);
- list1.add(sendPacket4);
-
- // 接收
- DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
-
- while(true) {
- // 发送
- System.out.print("我说:");
- String sendContent = input.nextLine();
- for(int i = 0; i < list1.size(); i++) {
- list1.get(i).setData(sendContent.getBytes());
- socket.send(list1.get(i));
- }
-
- // 接收
- socket.receive(receivePacket);
- String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
- String ip = receivePacket.getAddress().toString();
- if(receiveContent.equals("over")) {
- System.out.println(map.get(ip) + "已退出聊天!!!");
- break;
- }
- System.out.println(map.get(ip) + "说:" + receiveContent);
- }
-
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- public class Work {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
-
- Map<String, String> map = new HashMap<String, String>(){
- {
- put("/192.168.254.153", "**");
- put("/192.168.254.181", "**");
- put("/192.168.254.150", "**");
- put("/192.168.254.188", "**");
- }
- };
-
- List<DatagramPacket> list1 = new ArrayList<DatagramPacket>();
- try (DatagramSocket socket = new DatagramSocket(5555)){
-
- // 发送
- DatagramPacket sendPacket1 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.153", 9999));
- DatagramPacket sendPacket2 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.181", 8888));
- DatagramPacket sendPacket3 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.150", 7777));
- DatagramPacket sendPacket4 = new DatagramPacket(new byte[1024], 1024, new InetSocketAddress("192.168.254.188", 5555));
- list1.add(sendPacket1);
- list1.add(sendPacket2);
- list1.add(sendPacket3);
- list1.add(sendPacket4);
-
- // 接收
- DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
-
- while(true) {
- // 接收
- socket.receive(receivePacket);
- String receiveContent = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
- String ip = receivePacket.getAddress().toString();
- if(receiveContent.equals("over")) {
- System.out.println(map.get(ip) + "已退出聊天!!!");
- break;
- }
- System.out.println(map.get(ip) + "说:" + receiveContent);
- }
-
-
- // 发送
- System.out.print("我说:");
- String sendContent = input.nextLine();
- for(int i = 0; i < list1.size(); i++) {
- list1.get(i).setData(sendContent.getBytes());
- socket.send(list1.get(i));
- }
-
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。