网络编程套接字(Socket编程)
Socket:Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。
Socket API 分类:
1.UDP数据报套接字编程:
DatagramSocket 构造方法:
方法签名 方法说明 DatagramSocket() 创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口
(一般用于客户端)DatagramSocket(int
port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用
于服务端)DatagramSocket 方法:
方法签名 方法说明 void
receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻
塞等待)void send(DatagramPacket
p)从此套接字发送数据报包(不会阻塞等待,直接发送) void close() 关闭此数据报套接字 DatagramPacket 构造方法:
方法签名 方法说明 DatagramPacket(byte[]
buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在
字节数组(第一个参数buf)中,接收指定长度(第二个参数
length)DatagramPacket(byte[]
buf, int offset, int length,
SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节
数组(第一个参数buf)中,从0到指定长度(第二个参数
length)。address指定目的主机的IP和端口号DatagramPacket 方法:
方法签名 方法说明 InetAddress
getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取
接收端主机IP地址int getPort() 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号byte[] getData() 获取数据报中的数据 构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用InetSocketAddress 来创建。
InetSocketAddress API
InetSocketAddress ( SocketAddress 的子类 )构造方法:
方法签名 方法说明 InetSocketAddress(InetAddress addr, int port) 创建一个Socket地址,包含IP地址和端口号
示例一:实现一个回显服务(EchoServer)=》一发一收(发什么就返回什么)
UDP服务端代码实现:
package network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;// 站在服务器的角度: // 1. 源 IP: 服务器程序本机的 IP // 2. 源端口: 服务器绑定的端口 (此处手动指定了 9090) // 3. 目的 IP: 包含在收到的数据报中. (客户端的IP) // 4. 目的端口: 包含在收到的数据报中. (客户端的端口) // 5. 协议类型: UDP public class UdpEchoServer {// 进行网络编程, 第一步就需要先准备好 socket 实例~ 这是进行网络编程的大前提.private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}// 启动服务器.public void start() throws IOException {System.out.println("启动服务器!");// UDP 不需要建立连接, 直接接收从客户端来的数据即可while (true) {// 1. 读取客户端发来的请求DatagramPacket requestPacket = new DatagramPacket(new byte[1024], 1024);socket.receive(requestPacket); // 为了接受数据, 需要先准备好一个空的 DatagramPacket 对象, 由 receive 来进行填充数据// 把 DatagramPacket 解析成一个 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength(), "UTF-8");// 2. 根据请求计算响应(由于咱们这是一个回显服务, 2 省略)String response = process(request);// 3. 把响应写回到客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);}}// 由于是回显服务, 响应就和请求一样了.// 实际上对于一个真实的服务器来说, 这个过程是最复杂的. 为了实现这个过程, 可能需要几万行, 几十万行代码....public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();} }
代码解析:
UDP客户端代码实现:
package network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP;private int serverPort;// 站在客户端的角度:// 源 IP: 本机 IP// 源端口: 系统分配的端口// 目的 IP: 服务器的 IP// 目的端口: 服务器的端口// 协议类型: UDPpublic UdpEchoClient(String ip, int port) throws SocketException {// 此处的 port 是服务器的端口.// 客户端启动的时候, 不需要给 socket 指定端口. 客户端自己的端口是系统随机分配的~~socket = new DatagramSocket();serverIP = ip;serverPort = port;}public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true) {// 1. 先从控制台读取用户输入的字符串System.out.print("-> ");String request = scanner.next();// 2. 把这个用户输入的内容, 构造成一个 UDP 请求, 并发送.// 构造的请求里包含两部分信息:// 1) 数据的内容. request 字符串// 2) 数据要发给谁~ 服务器的 IP + 端口DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIP), serverPort);socket.send(requestPacket);// 3. 从服务器读取响应数据, 并解析DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);socket.receive(responsePacket);String response = new String(responsePacket.getData(), 0, responsePacket.getLength(), "UTF-8");// 4. 把响应结果显示到控制台上.System.out.printf("req: %s, resp: %s\n", request, response);}}public static void main(String[] args) throws IOException {// 由于服务器和客户端在同一个机器上, 使用的 IP 仍然是 127.0.0.1 . 如果是在不同的机器上, 当然就需要更改这里的 IP 了UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();} }
代码解析:
示例二:写一个简单的翻译程序(使用UDP协议)
UDP服务器代码:
package network;import java.io.IOException; import java.net.SocketException; import java.util.HashMap;public class UdpDictServer extends UdpEchoServer {private HashMap<String, String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);// 简单构造几个词dict.put("cat", "小猫");dict.put("dog", "小狗");dict.put("fuck", "卧槽");dict.put("pig", "小猪");}@Overridepublic String process(String request) {return dict.getOrDefault(request, "该词无法被翻译!");}public static void main(String[] args) throws IOException {UdpDictServer server = new UdpDictServer(9090);server.start();} }
注意:如果想要启动多个客户端,可以设置一下IDEA
2.TCP流套接字编程:
- ServerSocket API
- Socket API
ServerSocket API: ServerSocket 是创建TCP服务端Socket的API
ServerSocket 构造方法:
方法签名 方法说明 ServerSocket(int port) 创建一个服务端流套接字Socket,并绑定到指定端口 ServerSocket 方法:
方法签
名方法说明 Socket
accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket
对象,并基于该Socket建立与客户端的连接,否则阻塞等待void
close()关闭此套接字 Socket API: Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
Socket 构造方法:
方法签名 方法说明 Socket(String host, int
port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的
进程建立连接Socket 方法:
方法签名 方法说明 InetAddress getInetAddress() 返回套接字所连接的地址 InputStream getInputStream() 返回此套接字的输入流 OutputStream getOutputStream() 返回此套接字的输出流
示例一:写一个回显服务(使用TCP)
TCP服务端代码:
package network;import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;public class TcpEchoServer {// listen => 英文原意 监听~~// 但是在 Java socket 中是体现不出来 "监听" 的含义的~~// 之所以这么叫, 其实是 操作系统原生的 API 里有一个操作叫做 listen// private ServerSocket listenSocket = null;private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 由于 TCP 是有连接的, 不能一上来就读数据, 而要先建立连接. (接电话)// accept 就是在 "接电话", 接电话的前提是, 有人给你打了~~, 如果当前没有客户端尝试建立连接, 此处的 accept 就会阻塞.// accept 返回了 一个 socket 对象, 称为 clientSocket. 后续和客户端之间的沟通, 都是通过 clientSocket 来完成的.// 进一步讲, serverSocket 就干了一件事, 接电话~~Socket clientSocket = serverSocket.accept();processConnection(clientSocket);}}private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());// 接下来来处理请求和响应// 这里的针对 TCP socket 的读写就和文件读写是一模一样的!!try (InputStream inputStream = clientSocket.getInputStream()) {try (OutputStream outputStream = clientSocket.getOutputStream()) {// 循环的处理每个请求, 分别返回响应Scanner scanner = new Scanner(inputStream);while (true) {// 1. 读取请求if (!scanner.hasNext()) {System.out.printf("[%s:%d] 客户端断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());break;}// 此处用 Scanner 更方便. 如果不用 Scanner 就用原生的 InputStream 的 read 也是可以的String request = scanner.next();// 2. 根据请求, 计算响应String response = process(request);// 3. 把这个响应返回给客户端// 为了方便起见, 可以使用 PrintWriter 把 OutputStream 包裹一下PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);// 刷新缓冲区, 如果没有这个刷新, 可能客户端就不能第一时间看到响应结果.printWriter.flush();System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(),clientSocket.getPort(), request, response);}}} catch (IOException e) {e.printStackTrace();} finally {// 此处要记得来个关闭操作.try {clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();} }
代码解析:
TCP客户端代码:
package network;import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner;public class TcpEchoClient {// 用普通的 socket 即可, 不用 ServerSocket 了// 此处也不用手动给客户端指定端口号, 让系统自由分配.private Socket socket = null;public TcpEchoClient(String serverIP, int serverPort) throws IOException {// 其实这里是可以给的. 但是这里给了之后, 含义是不同的. ~~// 这里传入的 ip 和 端口号 的含义表示的不是自己绑定, 而是表示和这个 ip 端口建立连接!!// 调用这个构造方法, 就会和服务器建立连接 (打电话拨号了)socket = new Socket(serverIP, serverPort);}public void start() {System.out.println("和服务器连接成功!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream()) {try (OutputStream outputStream = socket.getOutputStream()) {while (true) {// 要做的事情, 仍然是四个步骤// 1. 从控制台读取字符串System.out.print("-> ");String request = scanner.next();// 2. 根据读取的字符串, 构造请求, 把请求发给服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);printWriter.flush(); // 如果不刷新, 可能服务器无法及时看到数据.// 3. 从服务器读取响应, 并解析Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();// 4. 把结果显示到控制台上.System.out.printf("req: %s, resp: %s\n", request, response);}}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();} }
代码解析:
问题:
方法一:使用多线程
方法二:使用线程池:
示例二:完成一个简单的翻译程序(使用TCP)
同样的也只需要修改TCP服务端即可
TCP服务端代码:
package network;import java.io.IOException; import java.util.HashMap;public class TcpDictServer extends TcpThreadPoolEchoServer {private HashMap<String, String> dict = new HashMap<>();public TcpDictServer(int port) throws IOException {super(port);dict.put("cat", "小猫");dict.put("dog", "小狗");dict.put("pig", "小猪");dict.put("fuck", "卧槽");}@Overridepublic String process(String request) {return dict.getOrDefault(request, "当前的词无法翻译");}public static void main(String[] args) throws IOException {TcpDictServer server = new TcpDictServer(9090);server.start();} }
代码解析:
网络编程套接字(Socket编程)相关推荐
- Java套接字Socket编程--TCP参数
在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...
- 网络编程套接字Socket
首先理解源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址 了解端口号 端口号(port)是传输层协议的内容 端口号是一个32位的整数 端口号用来标 ...
- 套接字Socket编程
Socket,原意插座.插口.写软件程序时,可以想象成一根网线,一头插在客户端,一头插在服务端,然后进行通信.所以通信前,双方都要建立一个Socket. Socket编程进行的是端到端的通信,意识不到 ...
- 网络 IPC 套接字socket
APUE书中所有实例源码下载地址:http://www.apuebook.com apue学习笔记(第十六章 网络IPC:套接字):https://www.cnblogs.com/runnyu/p/4 ...
- Linux - 第12节 - 网络编程套接字(一)
目录 1.预备知识 1.1.理解源IP地址和目的IP地址 1.2.理解源MAC地址和目的MAC地址 1.3.理解源端口号和目的端口号 1.4.理解端口号(PROT)和进程ID(PID) 1.5.认识T ...
- [python学习] 专题七.网络编程之套接字Socket、TCP和UDP通信实例
很早以前研究过C#和C++的网络通信,参考我的文章: C#网络编程之Tcp实现客户端和服务器聊天 C#网络编程之套接字编程基础知识 ...
- socket网络编程套接字TCP/UDP两种方式详解
目录 准备知识 源IP地址和目的IP地址 端口号与进程ID 传输层协议--TCP 传输层协议--UCP 网络字节序 socket套接字介绍 概念 常见的三种socket socket编程常见API s ...
- 网络编程:套接字socket函数与绑定信息bind函数
套接字socket函数与绑定信息bind函数 套接字 绑定信息(绑定IP和端口) socket函数 bind函数 struct sockaddr结构体的组成: struct sockaddr_in结构 ...
- Java网络编程入门,包含网络相关概念、InetAddress类、套接字Socket、网络上传和下载文件等
Java学习-11-韩顺平老师 Java-网络编程入门 目录: 01-网络相关概念 02-InetAddress类 03-套接字Socket 04-网络上传和下载文件 05-UDP网络编程 网络编程相 ...
最新文章
- Coolite Toolkit学习笔记五:常用控件Menu和MenuPanel
- 蓝桥杯练习系统习题-算法提高2
- 【转】JMeter学习(六)集合点
- sql drop 简单操作(Mysql)
- connectionstring mysql_Entity Framework 6 自定义连接字符串ConnectionString连接MySQL
- 解决vs2005中文乱码问题
- linux socket编程:简易客户端与服务端
- 粉刷匠(bzoj 1296)
- Android中设置位移动画的停止
- visa虚拟卡生成器_虚拟卡有哪些功能?赶紧了解一下
- 《C++ Primer 第5版》源码下载地址
- 这是互联网变得越来越敌对的7种方式
- 机顶盒ttl无法输入_中兴机顶盒B8601.1T TTL后跑码无法输入指令
- HiC-Pro | HiC数据处理工具
- python小游戏课程设计报告_贪吃蛇游戏课程设计报告
- 禁用MacOS系统自带输入法最简单的方法
- 晶闸管整流桥matlab仿真,matlab仿真模型作业
- 在Word文档中插入Excel表格时出现:“用于创建此对象的程序是Excel。您的计算机尚未安装此程序。”试试这个方法
- Linux日志文件系统
- 第二章 一种操作系统的诞生
热门文章
- 微机原理-80386(3)
- 云台山茶旅集团带您走进湘潭市的非法集资宣传活动
- English Learning - L2 语音作业打卡 复习双元音 [ɔɪ] [aʊ] 代词弱读技巧 Day49 2023.4.10 周一
- 代理模式——虚拟代理(结构型)
- 使用静态内部类单例模式创建自定义线程池
- tomcat中间件的默认端口号_tomcat端口号修改(tomcat默认端口号是多少)
- 中小企业如何实施股权激励
- 正则基础及常用正则式
- katalon实现读取excel中数据并自动上传
- 二维 Arnold 的图像置乱加密及解密——Matlab实现