当前位置: 首页 > wzjs >正文

自己做头像网站品牌设计得公司

自己做头像网站,品牌设计得公司,看到招聘游戏推广员千万别去,千库网app官方下载TCP的socket api 两个核心的类 ServerSocket 创建一个这样的对象,就相当于打开了一个socket文件。 这个socket对象是给服务器专门使用的 这个类本身不负责发送接收。 主要负责“建立连接” Socket 创建一个这样的对象,也就相当于打开了一个socket文…

TCP的socket api

两个核心的类

ServerSocket 

创建一个这样的对象,就相当于打开了一个socket文件。 这个socket对象是给服务器专门使用的 这个类本身不负责发送接收。 主要负责“建立连接”

Socket

创建一个这样的对象,也就相当于打开了一个socket文件。 这个类,服务器和客户端都会使用~ 这个类负责发送接收数据。

TCP是字节流的。 读写的时候,以字节byte为基本单位。 文件也是字节流的呀~ 读写tcp的代码,本质上就是和读写文件的代码是一致。 都是通过InputStream / OutputStream展开的

编写 TCP 版本的 echo server

作为回显服务器,客户端给服务器发的都是字符串,是可以按照字符流来处理的。

System.in 就是 InputStream

前面写了一个 UDP 服务器,端口是 9090。

现在有一个 TCP 服务器,端口也是 9090。

 是否冲突呢? 不会有冲突,因为是不同的协议。

最后面一栏的数字是进程的pid

package network.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 EchoServer {   private ServerSocket serverSocket ;public EchoServer(int port) throws IOException { //构造方法,初始化ServerSocket对象serverSocket = new ServerSocket(port); //创建ServerSocket对象,用于监听指定端口的连接请求}public void start() throws IOException { //启动服务器System.out.println("服务器启动!"); //打印服务器启动信息while (true) { //循环接收客户端连接请求Socket socket = serverSocket.accept(); //接收客户端连接请求,返回Socket对象,用于与客户端进行通信ProcessConnection(socket);}}private void ProcessConnection(Socket socket) throws IOException { //处理客户端连接请求System.out.printf("[%s:%d] 客户端上线!\n" , socket.getInetAddress().toString(),socket.getPort());try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) { //获取输入流,用于读取客户端发送的数据Scanner scanner = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);while (true) {//1.读取请求并解析if(!scanner.hasNext() ){break;//针对客户端下线逻辑的处理如果客户端断开连接了,比如客户端进程退出了,那么服务器这边就会收到一个EOF异常,//此时就应该把客户端的连接给关闭掉,这样服务器就可以继续等待下一个客户端的连接了。//如果是使用read方法,就会出现返回-1的情况,也可以用来判定客户端断开连接}String request = scanner.next(); //读取客户端发送的数据,返回字符串类型的请求//2.根据请求计算响应String response = process(request);//3.把响应写回客户端writer.println(response);//4.日志System.out.printf("[%s:%d] req:%s;resp:%s\n", socket.getInetAddress().toString(),socket.getPort(),request,response);}}catch (IOException e) {e.printStackTrace();               } //打印客户端上线信息}private String process(String request) { //处理请求,返回响应return request; //返回请求内容,作为响应内容}public static void main(String[] args) throws IOException {EchoServer server =  new EchoServer(9090);server.start();}
}

编写 TCP 版本的 echo client

TCP是有连接的, 一上来需要先进行"建立连接"操作。 建立连接是操作系统内核完成的,不需要我们写代码实现。 但是需要我们需要告知操作系统,服务器的IP和端口是什么

UDP协议本身,无连接的,UDP不记录对端的信息(UDP协议自身不关心服务器的ip和端口) 就需要在后面发送UDP数据报的时候,才能把服务器的IP端口指定进去.

可以针对控制台,可以针对文件,也能针对网络。

运行网络程序,一定是先启动服务器,后启动客户端。

还存在 3 个非常严重的问题.
(这个程序还跑不起来)

问题一:通信不通

客户端发了请求之后,没有收到响应。此时要排除主体,是客户端没把数据发出去,还是服务器收到了没有正确处理?

有人会问,是否可能丢包? 不可能,因为当前是自己给自己发送(客户端和服务器是在一台主机)

// 2. 构造请求发送给服务器. writer.println(request);

根据以上代码我们可以知道,实际上是没有客户端没有发送请求。

这涉及到缓冲区的问题。缓冲英文是buffer,广义的概念:通常情况下, buffer 就是一个"内存空间" 计算机读写内存,比读写外设,快很多。 假设要频繁写入多次, 每一次都写入网卡 还是把多次的数据攒一起,一次性写入网卡呢?答案毋庸置疑是后者。此处 println 是执行到了,但是 println 只是把数据先写到缓冲区中,没有真正的写入网卡,也就没有真正发送。如果缓冲区攒的满了, 就会自动触发写入,或者手动刷新缓冲区(此处我们采取这种方案来解决)。

  flush 原义 冲刷

问题二:当前程序中,存在"文件资源泄露"问题

每循环一次,就会触发一次 打开文件操作。(构造的 socket 对象) 一个服务器,不知道要处理多少个客户端, 导致打开操作频繁进行。

UDP 中涉及到 DatagramSocket,就没有关闭。
TCP 里还有 ServerSocket,也没有关闭。

这是因为UDP 的 socket 全局只有一个,不会频繁创建销毁,生命周期很长,只要服务器运行,就随时可能会使用。要关闭,只能在程序退出之前进行关闭。程序退出,就等于是进程结束。进程结束就会自动销毁文件描述符表中的所有内容了。 (相当于自动关闭了)

同理,对于 客户端的 DatagramSocket / Socket 也是一样。

这俩就可以不关闭了, 这俩对象实际上自身不持有文件描述。真正的文件描述符在 socket 对象里。

问题三:和程序运行效果直接相关

问题在于"多个客户端"的情况

只要第一个客户端不退出,processConnection的循环就不会结束,此时外层循环就无法第二次执行到 accept

那么如何能兼顾到里层循环和外层循环呢?利用线程,里层循环正常循环,处理客户端的多个请求。与此同时,外层循环也能继续执行,来accept下一个客户端。

多线程概念最初被发明出来,主要就是解决这个场景的问题的。给每个客户端都分配一个线程,由这个线程负责这个客户端的请求和响应。

如果,客户端数目非常多,那就会导致线程被频繁的创建销毁,这个时候我们可以使用线程池。

package network.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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class EchoServer {   private ServerSocket serverSocket ;public EchoServer(int port) throws IOException { //构造方法,初始化ServerSocket对象serverSocket = new ServerSocket(port); //创建ServerSocket对象,用于监听指定端口的连接请求}public void start() throws IOException { //启动服务器System.out.println("服务器启动!"); //打印服务器启动信息   ExecutorService threadPool = Executors.newCachedThreadPool();  while (true) { //循环接收客户端连接请求Socket socket = serverSocket.accept(); //接收客户端连接请求,返回Socket对象,用于与客户端进行通信// 修正:启动线程处理客户端连接//  Thread t = new Thread(() -> { //try {//   ProcessConnection(socket);// } catch (IOException e) {//     e.printStackTrace();//   }// });threadPool.submit(new Runnable() { // 新增:使用线程池处理客户端连接@Overridepublic void run() { // 新增:实现 run 方法,处理客户端连接请求try {ProcessConnection(socket); // 调用 ProcessConnection 方法处理客户端连接请求}catch (IOException e) { // 新增:捕获异常,打印异常信息e.printStackTrace(); // 新增:打印异常信息} // 新增:捕获异常,打印异常信息}});}}private void ProcessConnection(Socket socket) throws IOException { //处理客户端连接请求System.out.printf("[%s:%d] 服务端上线!\n" , socket.getInetAddress().toString(),socket.getPort());try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) { //获取输入流,用于读取客户端发送的数据Scanner scanner = new Scanner(inputStream);// 修正:启用自动刷新PrintWriter writer = new PrintWriter(outputStream, true); while (true) {//1.读取请求并解2析if(!scanner.hasNext() ){break;//针对客户端下线逻辑的处理如果客户端断开连接了,比如客户端进程退出了,那么服务器这边就会收到一个EOF异常,//此时就应该把客户端的连接给关闭掉,这样服务器就可以继续等待下一个客户端的连接了。//如果是使用read方法,就会出现返回-1的情况,也可以用来判定客户端断开连接}// 修正:使用 nextLine 读取完整输入if (!scanner.hasNextLine()) { break;}String request = scanner.nextLine(); String response = process(request);//3.把响应写回客户端writer.println(response);//4.日志System.out.printf("[%s:%d] req:%s;resp:%s\n", socket.getInetAddress().toString(),socket.getPort(),request,response);}}catch (IOException e) {e.printStackTrace();               } //打印客户端上线信息finally{// 修正:关闭当前客户端 socket,而非 serverSocketif (socket != null && !socket.isClosed()) {socket.close(); System.out.printf("[%s:%d] 客户端下线!\n", socket.getInetAddress().toString(), socket.getPort());}}}private String process(String request) { //处理请求,返回响应return request; //返回请求内容,作为响应内容}public static void main(String[] args) throws IOException {EchoServer server =  new EchoServer(9090);server.start();}
}

此处其实还有问题。假设有非常多的客户端,这些客户端连接之后,不会立刻销毁,而是会存在一定的时间。此时如果客户端很多,并且又不快速销毁,就会短时间内出现大量的线程。但是对于操作系统来说,线程的数目也不是无限的


文章转载自:

http://tMOz4neg.pbgnx.cn
http://tiMHM0Nr.pbgnx.cn
http://fLn9oSRU.pbgnx.cn
http://iTwXhhs2.pbgnx.cn
http://UPctBnAa.pbgnx.cn
http://29Z1dPu8.pbgnx.cn
http://sNMd4Ug4.pbgnx.cn
http://iUFHHdHF.pbgnx.cn
http://nZbzeeJh.pbgnx.cn
http://5sjkOHdO.pbgnx.cn
http://zIBHHAxD.pbgnx.cn
http://BVU5S6tg.pbgnx.cn
http://MFRBCTx4.pbgnx.cn
http://KhZt5WJ3.pbgnx.cn
http://Eba0s5Yr.pbgnx.cn
http://3nO8StQ0.pbgnx.cn
http://76mBYcXP.pbgnx.cn
http://bFBnKjKV.pbgnx.cn
http://wdylZCra.pbgnx.cn
http://COGD19VY.pbgnx.cn
http://Hhs2iu7Y.pbgnx.cn
http://FVQEugwx.pbgnx.cn
http://DhdACmAS.pbgnx.cn
http://datNy0il.pbgnx.cn
http://sMHMFxXd.pbgnx.cn
http://umpvJnXM.pbgnx.cn
http://eKiYCcHq.pbgnx.cn
http://swYSJcVF.pbgnx.cn
http://kUip7x5S.pbgnx.cn
http://HBYFcFTC.pbgnx.cn
http://www.dtcms.com/wzjs/669966.html

相关文章:

  • 网站建设与管理 中职wordpress批量修改文章分类
  • 做电脑网站步骤泰安网红餐厅
  • 做网站用什么虚拟主机网站搜索功能实现
  • 网站的基本组成部分有哪些织梦wap网站模版
  • 惠州seo代理计费永康网站优化公司
  • 酒店如何做网站北京南昌网站建设
  • 网站 php连接mysql 代码昆明seo网站建设
  • 郑州北环网站建设培训中小企业服务平台
  • 佛山seo网站优化中国建设银行内部网站
  • 比较好看的网站设计阳泉哪里做网站
  • 加强三农网站建设的意义方法网站目录
  • 网站结构分析动漫制作专业课程
  • 讨债公司 做网站wordpress数据库配置页面
  • 自己网站上放个域名查询建网站新科网站建设
  • 福州网站建设找嘉艺网络建设银行湖北省分行 网站
  • 网站建设需要注意哪些细节低价自适应网站建设优化建站
  • 用jsp做的可运行的网站广告线上推广方式
  • 地方门户网站发展趋势怎样做一个网站首页
  • 深圳企业网站备案图片网址生成器
  • 秦皇岛市建设局网站营销方案100例免费
  • 西数网站助手适合个人做的跨境电商平台
  • 简述网站建设的五类成员网上推广产品哪个平台效果好
  • 网站备案查询api网站产品页面什么时候做
  • 免费建网站的作用网站开发原始数据
  • 余江网站建设videojs wordpress
  • 网站内部优化的方法商业授权书
  • excel网站链接怎么做国际热点新闻
  • 优秀的图片设计网站推荐福田欧辉是国企吗
  • 网站推广seo设置网站排名降级的原因有哪些
  • 建设银行手机网站首页体育设施建设网站