Socket(四)

article/2025/9/27 8:49:18

文章目录

    • 1. 服务器Socket简介
    • 2. 使用ServerSocket
    • 3. 用Socket写入服务器
    • 4. 关闭服务器Socket

1. 服务器Socket简介

博客Socket(一)~Socket(二)从客户端的角度讨论了Socket,客户端就是向监听连接的服务器打开一个Socket程序。不过只有客户端Socket还不够,如果不能和服务器通信,客户端没有什么用处,所以服务器也要创建Socket,编写服务器时,无法预先了解哪个主机会联系你,即使确实知道,你也不清楚哪个主机希望和你连接。换句话说,服务器就像坐在电话旁等电话一样,不知道谁会打来电话,或者什么时间打电话,所以只用Socket类是不能做到这一点的。对于接受连接的服务器,Java提供了一个ServerSocekt类表示服务器Socket。服务器Socket在服务器上运行 ,监听入站TCP连接。每个服务器Socket监听服务器上的一个特定端口,当远程主机上的一个客户端尝试连接这个端口时,服务器就会被唤醒,协商建立客户端和服务器之间的连接,并返回一个常规的Socket对象,表示两个主机之间的Socket。换句话说,服务器Socket等待连接,而客户端Socket发起连接,一旦ServerSocket建立了连接,服务器会使用一个常规的Socket对象向客户端发送数据,数据总是通过常规的Socket传送。

2. 使用ServerSocket

ServerSocket类包含了使用Java编写服务器所需的全部内容,其中包括创建新ServerScoket对象的构造函数、在指定端口监听连接的方法、配置各个服务器Socket选项的方法,以及其他一些常见的方法,如tostring()。在java中程序的生命周期如下:

  1. 使用一个ServerSocket()构造函数在一个特定的端口创建一个新的ServerSocket
  2. ServerSocket使用其accept()方法监听这个端口的入站连接。accept()会一直阻塞,直到一个客户端尝试建立连接,此时accept()返回一个连接客户端和服务器的Socket对象
  3. 根据服务器的类型,会调用Socket的getInputStream()方法或getOutputStream()方法,或者这两个方法都使用,以获取与客户端通信的输入和输出流
  4. 服务器和客户端根据已协商的协议交互,直到要关闭连接
  5. 服务器或客户端(或二者)关闭连接
  6. 服务器返回步骤2,等待下一次连接

下面代码是daytime服务器的一个简单本地实现,首先是服务端代码

class myserver extends Thread{@Overridepublic void run(){try {System.out.println("服务器端开始运行:"+System.currentTimeMillis());ServerSocket serverSocket=new ServerSocket(8080);Socket connection=serverSocket.accept();OutputStream outputStream=connection.getOutputStream();Writer writer=new OutputStreamWriter(outputStream);Date now=new Date();writer.write(now.toString()+" 你龙哥服务器 "+"\r\n");writer.flush();connection.close();} catch (IOException e) {throw new RuntimeException(e);}}
}

我们首先让服务端运行,然后用telnet测试一下

在这里插入图片描述

然后是客户端代码

class User extends Thread{@Overridepublic void run(){try {System.out.println("客户端开始运行:"+System.currentTimeMillis());Socket socket=new Socket();SocketAddress socketAddress=new InetSocketAddress("127.0.0.1",8080);socket.connect(socketAddress);InputStream inputStream=socket.getInputStream();InputStreamReader reader=new InputStreamReader(inputStream);int c;StringBuilder mystring=new StringBuilder();while((c=reader.read())!=-1){mystring.append((char)c);}System.out.println(mystring);inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} }
}

最后是main函数代码

  public static void main(String[] args) throws InterruptedException {myserver server=new myserver();server.start();Thread.sleep(3000);User user=new User();user.start();}

查看运行结果

在这里插入图片描述

3. 用Socket写入服务器

在目前为止所有的例子中,服务器只写入客户端Socket,而没有从客户端读取,不过,大多数协议要求服务器同时读写客户端。这并不难,与从前一样,仍然要接受一个连接,不过这一次要同时获取一个InputStream和一个OutputStreamn。使用InputStream读取客户端,另外使用OutputStream写入客户端,关键是理解协议:明确何时写入和何时读取。RFC 862定义的echo协议是最简单的交互式TCP服务器,客户端打开指向echo服务器端口7的Socket,并发送数据,服务器将数据发回。这个过程一直继续,知道客户端关闭连接为止。 与Telnet的从控制体接受输入,把它发送给服务器,然后等待服务器读取返回一行输出不同,echo它会回显收到的每一个字节,它并不关心这些字节是否表示采用某种编码的字符,或者是划分为多行,与很多协议不同,echo没有指定锁步行为,即客户端发送一个请求,然后在发送更多数据之前会等待完整的服务器响应。echo协议需要客户端自己关闭连接。

下面是echo服务器的简单实现

public static void main(String[] args) throws InterruptedException {int port;try{port=8080;}catch (RuntimeException e){port=7;}System.out.println("Listening for connections on port  "+port);ServerSocketChannel serverSocketChannel;Selector selector;try{serverSocketChannel =ServerSocketChannel.open();ServerSocket ss=serverSocketChannel.socket();InetSocketAddress address=new InetSocketAddress(port);ss.bind(address);serverSocketChannel.configureBlocking(false);selector=Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);}catch (IOException e){e.printStackTrace();return;}while (true){try{selector.select();}catch (IOException e){e.printStackTrace();break;}}Set<SelectionKey> readyKeys=selector.selectedKeys();Iterator<SelectionKey> iterator=readyKeys.iterator();while(iterator.hasNext()){SelectionKey key=iterator.next();iterator.remove();try{if(key.isAcceptable()){ServerSocketChannel server=(ServerSocketChannel) key.channel();SocketChannel client=server.accept();System.out.println("Accepted connection from:"+client);client.configureBlocking(false);SelectionKey clientkey=client.register(selector,SelectionKey.OP_WRITE|SelectionKey.OP_READ);ByteBuffer buffer=ByteBuffer.allocate(100);clientkey.attach(buffer);}if(key.isAcceptable()){SocketChannel client=(SocketChannel) key.channel();ByteBuffer output=(ByteBuffer) key.attachment();client.read(output);}if(key.isWritable()){SocketChannel client=(SocketChannel) key.channel();ByteBuffer output=(ByteBuffer) key.attachment();output.flip();client.write(output);output.compact();}} catch (ClosedChannelException e) {throw new RuntimeException(e);} catch (IOException e) {key.cancel();try {key.channel().close();}catch (IOException ex){}}}}

当你运行这段代码时,它将创建一个简单的服务器端,用于监听指定的端口(默认为8080)上的连接。服务器使用非阻塞模式进行处理。

  • 首先,它尝试将端口设置为8080,如果出现RuntimeException异常,则将端口设置为7。
  • 然后,它打印一条消息,表示服务器正在监听指定端口上的连接。
  • 接下来,它创建一个ServerSocketChannel对象和一个Selector对象。它打开ServerSocketChannel并获取关联的ServerSocket对象。然后,它将ServerSocket绑定到指定的端口,并将ServerSocketChannel设置为非阻塞模式。最后,它将ServerSocketChannel注册到Selector上,关注连接请求事件。
  • 然后,代码进入一个无限循环,不断调用selector.select()方法来检查是否有就绪的事件发生。如果发生了IOException异常,循环会中断。
  • 在循环中,它获取就绪的SelectionKey集合,并遍历每个SelectionKey。根据SelectionKey的不同状态,它执行相应的操作:
  • 如果SelectionKey是可接受的(isAcceptable),表示有新的连接请求,它会接受连接,打印连接信息,并将新连接的SocketChannel注册到Selector上,关注读写事件。
  • 如果SelectionKey是可读的(isReadable),表示有数据可读取,它会读取数据到ByteBuffer中。
  • 如果SelectionKey是可写的(isWritable),表示可以写入数据,它会从ByteBuffer中取出数据并写入到SocketChannel中。
  • 在处理每个SelectionKey时,如果发生了ClosedChannelException异常,它会抛出RuntimeException异常。如果发生了IOException异常,它会取消该SelectionKey并关闭相应的通道。
  • 这个循环将一直执行,直到程序被终止。这样,服务器就可以接受并处理来自客户端的连接和数据。

注意:上面的代码涉及JavaNIO的知识

4. 关闭服务器Socket

如果使用完一个服务器Socket,就应当把它关闭,这个关闭Socket是不一样的,关闭ServerSocket会释放本地主机的一个端口,运行另一个服务器绑定到这个端口。他还会中断该ServerSocket已经接受的目前处于打开状态的所有Socket。程序结束时,服务器Socket会自动关闭,但手动关闭服务也是没有什么坏处,如下:

ServerSocket server=null;
try{server=new ServerSocket(port);}finally{if(server!=null){try{server.close();}catch(IOException ex){}}
}

可以使用无参数的ServerSocket()构造函数稍加改进,无参数构造函数不抛出任何异常,也不绑定到一个端口,你需要之后调用bind()方法来绑定一个Socket地址

ServerSocket server=new ServerSocket();
try{SocketAddress address=new InetSocketAddress(port);server.bind(address);}finally{if(server!=null){try{server.close();}catch(IOException ex){}}
}

http://chatgpt.dhexx.cn/article/ph4Nq08H.shtml

相关文章

CobaltStrike建立Socks4代理

目录 Socks4代理建立 ProxyChains的使用 Socks4代理建立 当我们的被控主机是位于公网和内网边界的服务器时&#xff0c;我们想利用该主机继续对内网的主机进行渗透&#xff0c;比如经过端口扫描我们发现被控机器的同一网段有一主机开放了80端口&#xff0c;我们想在本地访问…

Java常用工具类

学习内容 包装类型(基本数据类型的包装类型) String字符串常用方法 StringBuffer与Stringbuilder 日期和时间处理工具类 System,Math,Random,UUID等工具类 枚举类型 File类 递归算法 目录 1.包装类型 1.1.Integer的基本用法 1.2.包装类型的使用 1.3.自动装箱与自动…

Java——Collections工具类

Collections工具类 Collections 是一个操作 Set、List 和 Map 等集合的工具类 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作&#xff0c;还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。 排序操作&#xff1a;&#xff08;均为…

Spring自带的工具类

最近发现同事写了不少重复的工具类&#xff0c;发现其中很多功能&#xff0c;Spring 自带的都有。于是整理了本文&#xff0c;希望能够帮助到大家&#xff01; 目录 断言 对象、数组、集合 ObjectUtils StringUtils CollectionUtils 文件、资源、IO 流 FileCopyUtils R…

【常用工具类】Java控制台打印工具类LogUtil

文章目录 1 带分割线版2 不带分割线版3 终极版 1 带分割线版 import java.text.SimpleDateFormat; import java.util.Date;/*** W SKH 的输出工具类*/ public class LogUtil {private SimpleDateFormat simpleDateFormat new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss.SSS&…

Java 对象拷贝工具类

目录 1. Spring 中的对象拷贝 2. 本工具类中的对象拷贝 2.1 拷贝对象本身&#xff08;单个&#xff09; 2.2 拷贝对象本身&#xff08;批量&#xff09; 2.3 拷贝对象属性至其他类&#xff08;单个&#xff09; 2.4 拷贝对象属性至其他类&#xff08;批量&#xff09; 4.…

Java表达式运算工具类

对于表达式的运算转换工具类&#xff0c;使用场景&#xff0c;例如前端文本框让用户输入了加减乘除运算&#xff0c;工具类智能转换。 资源下载&#xff1a;Java表达式工具类&#xff0c;用于加减乘除等智能转换-Java文档类资源-CSDN下载 例如&#xff1a; public static void…

阿里OSS工具类

参考博客&#xff1a;阿里OSS入门 bucket配置信息&#xff1a;alios.properties OSS配置文件&#xff1a;AliOSSConfig.java Data public class AliOSSConfig {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketNam…

Guava Lists工具类

文章目录 01 概述02 Lists工具类03 文末 01 概述 Guava 是 Google 开源的一个 Java 工具库&#xff0c;里面有很多工具类&#xff0c;本文要讲的是里面的Lists工具类。 注意&#xff0c;使用Guava工具类库&#xff0c;必须先添加依赖&#xff1a; <dependency><gro…

JAVA之常用的工具类

目录 1 集合工具类 1.1 java.util.Collections 1.1.1 基本操作 1.1.2 转换线程安全集合 1.2 org.springframework.util.CollectionUtils 1.3 org.apache.commons.collections.CollectionUtils 1.4 org.apache.commons.lang.ArrayUtils 1.5 org.apache.commons.lang3.Ar…

常用的Java开发工具类

前言 在java的庞大体系中&#xff0c;其实有很多不错的小工具&#xff0c;也就是我们平常说的&#xff1a;轮子。 如果在我们的日常工作当中&#xff0c;能够将这些轮子用户&#xff0c;再配合一下idea的快捷键&#xff0c;可以极大得提升我们的开发效率。 今天我决定把一些…

工具类的详解

工具类网站 1、工具类 1.1 定义 工具类是为了提供一些通用的、某一非业务领域内的公共方法&#xff0c;不需要配套的成员变量&#xff0c;仅仅是作为工具方法被使用。所以将它做成静态方法最合适&#xff0c;不需要实例化&#xff0c;能够获取到方法的定义并调用就行。 1.2…

学习日记-安卓Package Manager和Package Installer

安装和卸载APK&#xff08;安卓应用程序包文件&#xff09;&#xff0c;运作原理。 什么是Package Manager&#xff08;包管理器&#xff09;和Package Installer&#xff08;程序安装包&#xff09;&#xff1f; APK文件保存在Android的哪个地方&#xff1f; APK文件安装过…

PackageInstaller (tv 修改安装app界面按钮及自动获取焦点)附源码分析

\packages\apps\PackageInstaller 一、一条真实的修改记录 TVOS基于的是一套板卡厂商原有的源码(mstar android8.0版本&#xff09;原生的这个app安装界面&#xff0c;存在俩个比较严重的用户体验问题&#xff0c; 1’、下面那俩按钮太小了&#xff0c;而且…

android packages/apps 加入工程,深入安卓Package Manager和Package Installer

我们每天都在安装和卸载APK(安卓应用程序包文件)&#xff0c;或许一天会有好几次&#xff0c;但是你有想过下面问题吗&#xff1f;什么是Package Manager(包管理器)和Package Installer(程序安装包)&#xff1f; APK文件保存在Android的哪个地方&#xff1f; APK文件安装过程的…

RK3568平台开发系列讲解(安卓篇)PackageInstaller(应用安装)流程介绍

文章目录 <font color=#0990d9>一、PackageInstaller入口<font color=#0990d9>二、InstallStart<font color=#0990d9>三、InstallStaging<font color=#0990d9>四、PackageInstallerActivity<font color=#0990d9>五、InstallInstalling<font c…

Android9.0 PM机制系列(一)PackageInstaller初始化解析

前言 包管理机制是Android中的重要机制&#xff0c;是应用开发和系统开发需要掌握的知识点之一。 包指的是Apk、jar和so文件等等&#xff0c;它们被加载到Android内存中&#xff0c;由一个包转变成可执行的代码&#xff0c;这就需要一个机制来进行包的加载、解析、管理等操作&…

PackageInstaller源码分析(一)

本篇博客分析PackageInstaller源码目的是分析Android权限机制&#xff0c;Android App的权限在应用被安装时&#xff0c;用户选择授予或者拒绝。所以&#xff0c;分析Android权限机制源码的第一步分析应用程序安装时的行为。   此次阅读源码旨在解决的问题&#xff1a;Andro…

A*B problem(FFT)

A*B problem&#xff08;FFT&#xff09; 设两个多项式\(A(x)\)和\(B(x)\)&#xff0c;它们的系数镜像反转一下&#xff0c;得到的多项式是\(A(x)\)和\(B(x)\)。那么\(C(x)A(x)*B(x)\)和\(C(x)A(x)*B(x)\)的系数也是镜像反转的。这个&#xff0c;&#xff0c;感性理解一下吧。 …

【kissfft】使用过程中的一些坑总结

API kissfft有两套API&#xff0c; 一个是在kiss_fftr.h中 另一个在kiss_fft.h中 区别 Basic API还是kiss_fft.h里的&#xff0c;kiss_fftr.h是在kiss_fft.h的基础上封装了一层。 Basic API只有fft没有见到ifft&#xff1f;&#xff1f; 利用频域数据的共轭对称性可以使用…