什么是Socket?

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

简单的来说,Socket就是套接字,由IP地址和端口号(范围是0~65535)组成,端口号是由操作系统随机分配的,但是小于1024的端口号是特权端口,一般都是需要管理员权限,用户使用时可能会和系统中某个应用程序发送冲突,因此,用户一般能随意使用的端口号都要大于1024。通过端口号,Socket才能正确连接本机中的应用程序。

那么如何来使用Socket来进行网络通信呢?其实需要两个Socket就可以了,一个Socket充当服务器端,一直处于监听指定端口状态,也就是ServerSocket,他的内容就是指定IP地址和指定端口号。另一个Socket充当客户端,必须主动连接服务器的IP地址和端口号,所以这个Socket的内容就是服务器的IP地址和服务器的端口号。这样客户端就和服务器实现了网络连接,从而能进行网络通信。

TCP编程

在网络协议中TCP协议是一种可靠传输、面向连接的协议,而TCP编程是使用TCP协议实现的,主要使用的就是Socket类,通过Socket可以建立服务器端与客户端的连接,从而实现客户端与服务器端的交互,比如人机问答等程序。

一个实例:TCP实现人机聊天程序

服务器端

准备一个Map集合,用来问题和答案,如果客户端发出的提问,问题库中没有,则返回null,

首先创建一个ServerSocket对象,监听9999端口,通过死循环使服务器一直处于监听状态,使用

accept()方法接收来自客户端的连接,返回Socket对象。

然后通过getInputStream()方法,获取到来自该Socket对象发出的的提问,并通过字符输入流进行包装,提高读取效率。

最后将从map集合中找到的答案,封装到字符输出流中,通过getOutputStream()方法返回给Socket对象。实现一次问答流程。代码如下:

package com.fulian.tcp.demo02;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;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(9999)) {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) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

客户端

首先创建一个Socket对象,传入服务器IP地址和端口号,通过Scanner对象获取用户提问。

然后通过getOutputStream输出流,将问题发往指定Socket对象,这里使用BufferedWriter进行包装。

发送完毕后,调用shutdownOutput(),暂停结束本次输出,可以理解为:客户端结束发送告知服务器:我发完了。

服务器端响应后,通过getOutputStream()输入流,返回给客户端答案这里使用BufferedReader进行包装。实现一次问答流程。代码如下:

package com.fulian.tcp.demo02;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;public class ChatClient {public static void main(String[] args) {Scanner input = new Scanner(System.in);while (true) {// 创建Scoket,连接服务器try (Socket client = new Socket("192.168.254.169", 9999);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) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println("Game over!");}
}

运行结果:

UDP编程

在网络协议中TCP协议是一种簿可靠传输、面无连接的协议,而UDP编程是使用UDP协议实现的,既然UDP协议是无连接的,那么就不能使用流进行网络通信,因此就只能使用数据包进行网络通信。使用UDP编程可以实现客户端与客户端之间的通信,比如一对一模拟聊天程序、一对多模拟对讲机程序等。

一个实例:发送端和接收端的聊天程序

发送端

首先,创建一个Socket监听8100端口(本机),这里的Socket是DatagramSocket,内部封装UDP协议。并提前创建了两个数据包DatagramPacket,sendPacket发送包:包括一个byte数组(缓冲区,用于存放发送到接收端的数据),和接收端的IP地址和端口号(8101),receivePacket接收包:包括一个空数组(缓冲区,用于接收到接收端的数据)。

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

接收数据时:通过receive(receivePacket)方法,将接收到的内容传入之前receivePacket包定义的空数组,如果收到的是字符串,通过DatagramPacket返回的getOffset()和getLength()确定数据在缓冲区的起止位置,并转成字符串,实现数据的接收。实现一次聊天,代码如下:

package com.fulian.udp.demo02;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;public class ChatA {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 客户端A监听8100端口try (DatagramSocket socket = new DatagramSocket(8100);){// 提前创建两个Packet数据包,分别用于发送和接收DatagramPacket sendPacket = new DatagramPacket(new byte[1024],1024, // 数据new InetSocketAddress("192.168.254.136", 8101)); // 目的地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("你已退出聊天!");break;}// 接收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) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

接收端

整体思路和发送端一致,但是流程是先接收再发送。代码如下:

package com.fulian.udp.demo02;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;public class ChatB {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 客户端B监听8101端口try (DatagramSocket socket = new DatagramSocket(8101);){// 提前创建两个Packet数据包,分别用于发送和接收DatagramPacket sendPacket = new DatagramPacket(new byte[1024],1024, // 数据new InetSocketAddress("192.168.254.136", 8100)); // 目的地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("你已退出聊天!");break;}}} catch (SocketException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

运行结果:

另一个实例:多人对讲机

思路:实现多人对讲机功能,先准备一个map集合,组内成员的IP地址作为键,DatagramPacket发送包作为值,存放组内成员的IP地址和端口,可以将发送端定义成管理员,管理员先作为发送端进行发送,其他用户作为接收端进行监听,每个用户在发送和接收时处于一直循环状态,当听到某条指令比如“over”时,其他用户会进行判断,进行管理员权限转让,从而实现对讲功能。

代码如下:

首位管理员(先作为发送端)

package com.fulian.udp.demo03;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;public class ChatA {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 客户端A监听8100端口(首位管理员)try (DatagramSocket socket = new DatagramSocket(8100);){// 提前创建两个Packet数据包,分别用于发送和接收// map集合存放组内成员的IP地址和端口Map<String, DatagramPacket> map = new LinkedHashMap<String, DatagramPacket>(){{put("192.168.254.162",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.162", 8101)));put("192.168.254.168",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.168", 8102)));put("192.168.254.158",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.158", 8103)));put("192.168.254.120",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.120", 8104)));put("192.168.254.136",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.136", 8105)));}};DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);Set<Entry<String, DatagramPacket>> set = map.entrySet();while(true) {while(true) {// 发送System.out.print("你说:");String sendContent = input.nextLine();for(Entry<String, DatagramPacket> e : set) {e.getValue().setData(sendContent.getBytes());socket.send(e.getValue());}// 当发送的内容是“over其他用户”时结束发言if(sendContent.equals("overB") || sendContent.equals("overC") ||sendContent.equals("overD") || sendContent.equals("overE") ) {System.out.println("结束发言!");break;}}// 接收while(true) {socket.receive(receivePacket);String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());// 当监听到的内容是“overA”时发言if(receiveContent.endsWith("overA")) {System.out.println("开始发言");break;}System.out.println(receivePacket.getAddress() + ":" + receiveContent);}}} catch (SocketException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

组内成员(先作为接收端)

package com.fulian.udp.demo03;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;public class ChatF {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 客户端F监听8105端口try (DatagramSocket socket = new DatagramSocket(8105);){// 提前创建两个Packet数据包,分别用于发送和接收// FMap<String, DatagramPacket> map = new LinkedHashMap<String, DatagramPacket>(){{put("192.168.254.162",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.162", 8101)));put("192.168.254.168",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.168", 8102)));put("192.168.254.158",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.158", 8103)));put("192.168.254.120",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.120", 8104)));put("192.168.254.136",new DatagramPacket(new byte[1024],1024,new InetSocketAddress("192.168.254.136", 8100)));}};DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);Set<Entry<String, DatagramPacket>> set = map.entrySet();while(true) {// 接收while(true) {socket.receive(receivePacket);String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());// 当监听到的内容是“overF”时发言if(receiveContent.endsWith("overF")) {System.out.println("开始发言");break;}System.out.println(receivePacket.getAddress() + ":" + receiveContent);}while(true) {// 发送System.out.print("你说:");String sendContent = input.nextLine();// Afor(Entry<String, DatagramPacket> e : set) {e.getValue().setData(sendContent.getBytes());socket.send(e.getValue());}// 当发送的内容是“over其他用户”时结束发言if(sendContent.equals("overA") || sendContent.equals("overB") || sendContent.equals("overC") ||sendContent.equals("overD") || sendContent.equals("overE") ) {System.out.println("结束发言!");break;}}}} catch (SocketException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

Java中的网络编程(TCP与UDP)相关推荐

  1. 学习Java第十九天(一):1、Java中的网络编程

    1.Java中的网络编程 什么是网络? 在计算机领域中网络是信息传输,接收共享的虚拟平台,通过它把各个点,面,体的联系到一起,从而实现这些资源的共享. 作用:信息传输,资源共享 有点:资源共享免费 O ...

  2. Java中的网络编程类(TCPUDP)

    Java中的网络编程类 n Java.net包 – TCP协议 URL URLConnection Socket ServerSocket – UDP协议 DatagramPacket Datagra ...

  3. 第78节:Java中的网络编程(上)

    第78节:Java中的网络编程(上) 前言 网络编程涉及ip,端口,协议,tcp和udp的了解,和对socket通信的网络细节. 网络编程 OSI开放系统互连 网络编程指IO加网络 TCP/IP模型: ...

  4. QT入门第七天 网络编程TCP/IP/UDP+Http和JSON解析+qt事件软键盘【CSDN最详细】

    网络编程+Http和JSON解析+qt事件软键盘 第一章 QT中的网络编程 [1]涉及到的类 [2]tcp协议的流程 [2.1]服务器的流程 socket-->bind-->listen- ...

  5. java 中的网络编程(Socket、TCP三次握手四次挥手、TCP/UDP/URL)

    文章目录 前言 一.网络编程概述 二.网络通信要素概述 1.如何实现网络中的主机互相通信 2.网络通信协议 3.IP和端口号 4.InetAddress类 5.网络协议 6.TCP/IP协议簇 7.T ...

  6. java socket ip_JAVA 网络编程 TCP/IP、Socket 和协议设计

    [JAVA 网络编程 TCP/IP.Socket 和协议设计] TCP/IP 协议简介 IP 首先我们看 IP(Internet Protocol)协议.IP 协议提供了主机和主机间的通信. 为了完成 ...

  7. Python网络编程——TCP与UDP

    Python网络编程 TCP(复杂可靠)与UDP(简单不可靠)的区别 1) TCP提供面向连接的传输,通信前要先建立连接(三次握手机制): UDP提供无连接的传输,通信前不需要建立连接. 2) TCP ...

  8. java全双工_java网络编程TCP聊天全双工

    我正在实现服务器和客户端之间的简单TCP聊天.我使用多线程,因此服务器和客户端可以同时发送和接收数据(全双工).该程序可以工作,但如果服务器有一个控制台既可以输入发送消息,也可以显示接收消息(对于客户 ...

  9. 大数据 -- java基础16 网络编程 TCP UDP

    1.网络编程的三要素:(1)IP地址(2)端口号(3)协议 2.IP地址 : 网络中计算机唯一标识. (1)IP地址在计算机中存储的时候是由二进制的形式进行存储的:IP:192.168.7.42 十进 ...

最新文章

  1. 身边的隐形富豪,都有哪些特征?
  2. java shape_Java 读取shape文件
  3. Set 的合集 并集 差集
  4. 摔跤视频软件测试,Apple Watch 4摔倒检测立功:成功救人一命,网友:马上入手!...
  5. php如果能编译就完美了,centos7 完美编译PHP7 php-7.2.10.tar.gz
  6. 使用异步 I/O 大大提高应用程序的性能(来自IBM)
  7. 操作系统—数组的定义和存储结构
  8. Springboot之添加本地模块依赖
  9. Ubuntu18环境下安装ROS
  10. python求解LeetCode习题Maximum Gap
  11. matlab的小波分析,MATLAB小波分析学习.pdf
  12. 一款不错的远程控制软件,还是绿色版哦
  13. python爬虫入门 之 requests 模块
  14. Android 第三方应用广告拦截实现
  15. 原生小程序实现手风琴
  16. Java调用不同的打印机实现打印不同小票
  17. 【二 HLS】HLS接口的简单介绍
  18. Kaggle手机验证manually verified
  19. SQL Server(解决问题)已成功与服务器建立连接,但是在登录过程中发生错误
  20. window下配置qemu虚拟机联网

热门文章

  1. Android游戏开发之数独课时----2
  2. 【Python】Matplotlib画图(二)——根据函数公式画图
  3. Javascript:ES6-ES11(2)
  4. jquery回弹_jQuery实现移动端下拉展现新的内容回弹动画
  5. AVI格式转换问题采用mediacoder和图片转换成AVI的makeavi软件
  6. 傲视群雄,酷派大神发力高端市场
  7. jsp创建mysql数据库_使用 MySQL 数据库创建简单的 JSP 应用程序(1)
  8. BIM模型文件下载——某高层办公楼Revit模型
  9. Windows下bat批处理脚本常用场景整理,持续更新中。。。
  10. 纯CSS在div上面添加小三角