【JavaEE初阶系列】——网络编程 TCP客户端/服务器 程序实现

目录

🚩TCP流套接字编程

🍭ServerSocket API

🍭Socket API

🍭TCP服务器

🍭TCP客户端


🚩TCP流套接字编程

俩个关键的类 

  • ServerSocket (给服务器使用的类,使用这个类来绑定端口号)
  • Socket(既会给服务器用,又会给客户端用)

这俩个类都是用来表示socket文件的。(抽象了网卡这样的硬件设备)


🍭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是有连接的,连接就意味着通信双方会记录保存对端的信息,UDP来说,每次发送数据都得手动send方法中指定目标地址(UDP自身没有存储这个消息)TCP来说,则不需要,前提是需要先把连接给建立上。那么,如果建立连接呢?不需要代码干预,是系统内核自动负责完成的,对应app来说,客户端这边,主要是要发起”建立连接"动作,服务器这边,主要要把建立好的连接从内核中拿到app里。

我们看到大型商场里,都有很有海底捞,每天海底捞的人是非常多的,你要想去吃海底捞,就要排号。我们给海底捞店当作应用程序。而内核就是一个队列等待着去吃海底捞,每当有客人吃完,走了,空出了一桌,服务员就会叫号。

如果有客户端和服务器建立连接,这个时候服务器的应用程序是不需要任何操作(也没有任何感知的),内核直接完成了连接建立的流程(三次握手),完成流程之后,就会在内核的队列中(这个队列是每个serverSocket都有一个这样的队列)排队。

应用程序要想和客户端进行通信,就需要通过一个accept方法把内核队列里已经建立好的连接对象,拿到app中。


TCP中用ServerSocket (给服务器使用的类,使用这个类来绑定端口号),服务器启动之后用到accept方法,把内核中建立好的连接到应用程序中去(建立连接的过程是内核自动完成的,应用程序是捡漏的),如果没有与客户端连接,那么就阻塞等待。

  private ServerSocket serverSocket=null;public TCPEchoServer(int port) throws IOException {serverSocket =new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器正式启动");while (true){//通过accpet方法,把内核中已经建立好的连接拿到app中//建立连接的细节流程都是内核自动完成的,app只需要“捡现成”的Socket clientSocket=serverSocket.accept();}}

在销售A卖楼盘的时候,销售在路上看到一个人想找一个人问问需不需要买房,然后那个男生就带去楼盘区,然后销售找了一个专业的置业顾问B,来介绍楼盘。而这个销售就去路上继续找人。

A:在外面招揽客人

B:给客人提供详细的服务

然后我们调用方法来处理当前的连接。首先我们先打印一个日志,表示已经与客户端建立连接了。

  • getPort() 和 getInetAddress() 得到对端的IP和端口 (客户端)
  • getLocalAddress() 和getLocalPort() 得到本地的IP和端口(服务器)
 //打印这个日志,来表示客户端连上了System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());

  • 首先我们接收请求,用Scanner包装输入流,并读取请求。
  • 然后我们根据请求,计算响应
  • 最后把响应写回客户端 ,用PrintWriter类进行包装输出流,并flush().
 Scanner scanner=new Scanner(inputStream);//1.读取请求并解析,此处就以next来作为读取请求的方式,.next的规则是,读到“空白符”就返回String request=scanner.next();//2.根据请求,计算响应String response=process(request);
//3.把响应写回客户端//可以把String转成字节数组,写入到OutputStream,
//也可以使用PrintWriter把OutputStream包裹一下,来写入字符串PrintWriter printWriter=new PrintWriter(outputStream);
//此处的println不是打印到控制台了,而是写入到outputStream对应的流对象,也就是写入到clientSocket
//自然这个数据也就通过网络发送出去了,//此处使用println带有\n 也是为了后续 客户端这边 可以使用 scanner.next来读取数据printWriter.write(response);

空白符 是一类特殊的字符,换行,回车符,空格,制表符,翻页符,垂直制表符

后续客户端发起的请求,会以空白符作为结束标记(此处就约定使用\n)


🍭TCP服务器

package TCP;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 {private ServerSocket serverSocket=null;public TCPEchoServer(int port) throws IOException {serverSocket =new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器正式启动");while (true){//通过accpet方法,把内核中已经建立好的连接拿到app中//建立连接的细节流程都是内核自动完成的,app只需要“捡现成”的Socket clientSocket=serverSocket.accept();Thread t=new Thread(()->{processConnection(clientSocket);});t.start();}}//通过这个方法,来处理当前的连接public void processConnection(Socket clientSocket) {//打印这个日志,来表示客户端连上了System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()) {//使用try()方式,避免后续用完了流对象,忘记关闭//由于客户端发来的数据,可能是"多条数据“,针对多条数据,就循环处理while (true){Scanner scanner=new Scanner(inputStream);if(!scanner.hasNext()){//连接断开了,此时循环就应该结束System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());break;}//1.读取请求并解析,此处就以next来作为读取请求的方式,.next的规则是,读到“空白符”就返回String request=scanner.next();//2.根据请求,计算响应String response=process(request);//3.把响应写回客户端//可以把String转成字节数组,写入到OutputStream,//也可以使用PrintWriter把OutputStream包裹一下,来写入字符串PrintWriter printWriter=new PrintWriter(outputStream);//此处的println不是打印到控制台了,而是写入到outputStream对应的流对象,也就是写入到clientSocket//自然这个数据也就通过网络发送出去了,//此处使用println带有\n 也是为了后续 客户端这边 可以使用 scanner.next来读取数据printWriter.println(response);//此处还要记得有个操作,刷新缓冲区,如果没有刷新操作,可能数据仍然是在内存中,没有被写入网卡printWriter.flush();//打印了这次请求交互过程的内容System.out.printf("[%s:%d] req=%s resp=%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}finally {//进行clientSocket的关闭try {clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public String process(String request){return request;}public static void main(String[] args) throws IOException {TCPEchoServer tcpEchoServer=new TCPEchoServer(9090);tcpEchoServer.start();}
}

如果我们出现了多个客户端连接同一个服务器该怎么办呢?这就考虑到多线程的知识了,如果有客户端就开启线程。


🍭TCP客户端

  private Socket socket=null;public TCPClient(String serverIP, int serverPort) throws IOException {//需要在创建Socket的同时,和服务器”建立连接“ 此时就得告诉Socket服务器在哪里//具体建立连接的细节,不需要咱们代码手动干预,是内核自动负责的//当我们new这个对象的时候,操作系统内核,就开始使用 三次握手 具体细节 完成建立连接的过程socket =new Socket(serverIP,serverPort);}

TCP是连接的,我们需要对端的IP和端口号。所以我们要构造服务器的IP和端口号。

客户端是发出请求,并接收服务器返回的响应。

  • 我们先输入,并判断是否有输入,如果有输入就返回字符串。
  • 发出请求,就是用PrintWriter类来封装输出流,并flush()。
  • 然后接收服务器返回的响应,用Scanner来封装输入流。然后调用next()方法返回String字符串
  • 然后打印处理。
package TCP;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 TCPClient {private Socket socket=null;public TCPClient(String serverIP, int serverPort) throws IOException {//需要在创建Socket的同时,和服务器”建立连接“ 此时就得告诉Socket服务器在哪里//具体建立连接的细节,不需要咱们代码手动干预,是内核自动负责的//当我们new这个对象的时候,操作系统内核,就开始使用 三次握手 具体细节 完成建立连接的过程socket =new Socket(serverIP,serverPort);}public void start(){System.out.println("客户端启动");//tcp客户端行为和udp客户端差不多//从服务器读取响应//把响应显示到界面上Scanner scanner=new Scanner(System.in);try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()) {Scanner scanner1=new Scanner(inputStream);while (true){//1.从控制台输入内容System.out.println("->");String request=scanner.next();//2.把字符串作为请求,发送给服务器PrintWriter printWriter=new PrintWriter(outputStream);printWriter.println(request);printWriter.flush();//3.读取服务器返回的响应String response=scanner1.next();//4.界面显式内容System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TCPClient tcpClient=new TCPClient("172.20.10.2",9090);tcpClient.start();}
}

你跑的快,耳边全是风声。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/306563.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024接口自动化测试入门基础知识【建议收藏】

接口自动化测试是指通过编写测试脚本和使用相关工具,对软件系统的接口进行自动化测试的过程。 今天本文从4个方面来介绍接口自动化测试入门基础知识 一、接口自动化测试是什么? 二、接口自动化测试流程? 三、接口自动化测试核心知识点有那些…

MySQL一些特殊功能的索引(6/16)

特殊功能性索引 B-Tree索引: InnoDB的默认索引类型,适用于多种查询操作。 可以用于等值查询、范围查询和索引列的组合查询。 创建B-Tree索引的示例: CREATE INDEX index_name ON table_name (column1, column2);全文索引(FULLTEX…

力扣207.课程表

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。 例如…

基于springboot实现教师人事档案管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现IT技术交流和分享平台系统演示 摘要 我国科学技术的不断发展,计算机的应用日渐成熟,其强大的功能给人们留下深刻的印象,它已经应用到了人类社会的各个层次的领域,发挥着重要的不可替换的作用。信息管理作为计算…

事务,MySQL函数和索引详解

文章目录 事务简介提交方式手动提交事务 事务执行流程修改事务的默认提交方式 事务原理四大特性隔离级别 MySQL函数常见的日期函数判断函数case when字符串函数数字函数 MySQL性能(了解)索引概念分类MySQL索引语法数据结构(了解)BTreeBTree好处 优缺点优势劣势 创建原则 事务简…

python中time库的time.time()函数的作用是什么?

python中time库的time.time()函数的作用是什么? 作用:Python time time() 返回当前时间的时间戳(1970纪元后经过的浮点秒数)。 time()方法语法:time.time() #!/usr/bin/python # Write Python 3 code in this onlin…

【LeetCode】动态规划类题目详解

所有题目均来自于LeetCode,刷题代码使用的Python3版本 动态规划 问题分类 如果某一个问题有重叠的子问题,则使用动态规划进行求解是最有效的。 动态规划中每一个状态一定是由上一个状态推导出来的,这一点区别于贪心算法 动态规划五部曲 确…

【JMeter】JMeter控制RPS

一、前言 ​ RPS (Request Per Second)一般用来衡量服务端的吞吐量,相比于并发模式,更适合用来摸底服务端的性能。我们可以通过使用 JMeter 的常数吞吐量定时器来限制每个线程的RPS。对于RPS,我们可以把他理解为我们的TPS,我们就不…

初识SpringMVC

一、什么是MVC MVC是一种软件架构模式(是一种软件架构设计思想,不止Java开发中用到,其它语言也需要用到),它将应用分为三块: M:Model(模型)V:View&#xff08…

Centos7 K8S 集群 - kubeadm搭建方式

机器准备 搭建环境是centos7, 四核心4G内存四台机器 一个master节点,一个etcd,两台node 机器名称IP 地址master192.168.1.127node1192.168.1.129node2192.168.1.130node3192.168.1.131 机器时间同步 各节点时间要求精确同步,可以直接联网…

游标的定义和类型

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 游标的基本概念 游标从字面上理解为游动的光标,可以使用 Excel 表格来想象游标的作用,游标指向每一行,通过游标访问每行数据。 在 Orac…

6.3Python之字典的内置方法

1、创建字典 dict.fromkeys() :可将列表、元组、集合转为字典 knowledgeL [语文, 数学, 英语] scoresD1 dict.fromkeys(knowledgeL, 60) print(scoresD1) knowledgeT (Chinese, Math, English) scoresD2 dict.fromkeys(knowledgeT, 60) print(scoresD2) knowl…

【Web】CTFSHOW-ThinkPHP5-6反序列化刷题记录(全)

目录 web611 web612 web613-622 web623 web624-626 纯记录exp&#xff0c;链子不作赘述 web611 具体分析&#xff1a; ThinkPHP-Vuln/ThinkPHP5/ThinkPHP5.1.X反序列化利用链.md at master Mochazz/ThinkPHP-Vuln GitHub 题目直接给了反序列化入口 exp: <?ph…

Web中使用Weblogic用户

WebLogic用户&#xff0c;组设置 1. 登录weblogic console, domain结构中选择Security Realms&#xff0c;显示安装时默认创建的Realm &#xff1a; myrealm 2. 点击myrealm, 选择 users and Group&#xff0c; 追加用户和组 选择既存的权限组追加到新规的组中&#xff0c;赋予…

面试:如何设计一个注册中心?

大家好&#xff0c;我是田哥 上周&#xff0c;一位群里的朋友反馈面试情况&#xff1a; 今天&#xff0c;给大家分享如何设计一个注册中心。其实这个问题&#xff0c;我之前在知识星球里分享过&#xff0c;可能是因为时间比较久了&#xff0c;加上这位朋友加入不久&#xff0c;…

力扣HOT100 - 160. 相交链表

解题思路&#xff1a; /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if…

雨云:不一样的服务器体验

引言 在当今数字化时代&#xff0c;服务器已经成为了许多企业和个人不可或缺的一部分。无论是建立网站、存储数据还是运行应用程序&#xff0c;都需要一个稳定可靠的服务器来支持。然而&#xff0c;在众多的服务器提供商中&#xff0c;选择一个适合自己需求的并不容易。今天我要…

spispi

数据手册里面有这么一段解释&#xff0c;就是说如果我们开启了看门狗&#xff0c;那么LSI就会跟随强制打开&#xff0c;等待LSI稳定之后就可以自动为独立看门狗提供时钟了。所以这里的第一步开启时钟不需要我们写代码来执行 2.写入预分频器和重装寄存器 在写入这两个寄存器之前…

git知识

如何将develop分支合并到master分支 #简单版 git checkout master git pull origin master git merge origin/develop # 解决可能的冲突并提交 git push origin master#复杂版 git checkout master # 拉取远程 master 分支的最新代码并合并到本地 git pull origin master # 拉…

Linux:软件包管理器 - yum

Linux&#xff1a;软件包管理器 - yum Linux的软件安装方式源代码安装rpm包安装yum安装 yum三板斧yum listyum installyum remove yum生态yum源 Linux的软件安装方式 源代码安装 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序 源代码安…