Java网络编程二:Socket详解

Socket又称套接字,是连接运行在网络上两个程序间的双向通讯的端点。

一、使用Socket进行网络通信的过程

服务端:服务器程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户端的连接请求。

客户端:客户端程序根据你服务器所在的主机名和端口号发出连接请求。

两者之间的通信是通过Socket完成的,我们可以认为Socket是两个城市之间的交通工具,有了它,就可以在两个城市之间穿梭了。

Socket通信示例

主机A的应用程序和主机B的应用程序通信,必须通过Socket建立连接,而建立Socket必须由底层的TCP/IP协议来建立TCP连接。建立TCP连接需要底层IP协议来寻址网络中的主机。IP地址只能帮助我们找到目标主机,但是一个主机上面有多个应用程序,如何才能找到我们需要的应用程序,这个时候就可以通过端口号来指定了。 

二、简易服务端、客户端模拟

服务器端:

 1     public static void main(String[] args) throws IOException
 2     {
 3         //创建一个ServerSocket,用于监听客户端Socket连接请求
 4         ServerSocket ss = new ServerSocket(8888);
 5         System.out.println("server start");
 6         //采用循环方式监听客户端的请求
 7         while(true)
 8         {
 9             //侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
10             Socket socket = ss.accept();
11             OutputStream os = socket.getOutputStream();
12             PrintStream ps = new PrintStream(os);
13             ps.print("您好,您收到了来自服务端的中秋祝福");
14             ps.close();
15             os.close();
16             socket.close();
17         }
18     }

执行结果:

server start

客户端:

 1     public static void main(String[] args) throws IOException, Exception
 2     {
 3         Socket socket = new Socket("localhost",8888);
 4         InputStream is = socket.getInputStream();
 5         BufferedReader br = new BufferedReader(new InputStreamReader(is));
 6         String str = br.readLine();
 7         System.out.println(str);
 8         br.close();
 9         is.close();
10         socket.close();
11     }

执行结果:

您好,您收到了来自服务端的中秋祝福

1、上面展示的是一个简易的服务端和客户端通信的建立过程。

2、我们通过交互图来详细介绍这个过程:

    

3、首先在server端,指定端口号创建serverSocket对象,通过serverSocket的accpet方法获取套接字,这个方法的特点是:侦听并接受到此套接字的连接,此方法在连接传入之前一直阻塞。这也就意味着,如果没有客户端连接请求过来,服务端会一致阻塞在这里。

4、后面的代码就是通过套接字socket可以得到输入输出流,到此为止,就是I/O的内容了。

5、在客户端这边,通过指定的服务器主机名和服务器监听的端口号,得到套接字Socket,这个时候就表示服务端和客户端的连接已经建立了,然后通过输入输出流来进行通信了。

三、半关闭的socket

  在上面的Demo中,我们是以行作为通信的最小数据单位,服务器端也是逐行进行处理的。但是我们在大多数场景下,通信的数据单位是多行的,这时候Socket的输出流如何表达输出的数据已经结束?

  在IO学习过程中提到过,如何要表示输出已经结束,则通过关闭输出流来实现,但是在socket中是行不通的,因为关闭socket,会导致无法再从该socket中读取数据了。为了解决这种问题,java提供了两个半关闭的方法:

1、shutdownInput():关闭该Socket的输入流,程序还可以通过该Socket的输出流输出数据。

2、shutdownOutput():关闭该Socket的输出流,程序还可以通过该Socket的输入流读取数据。

如果我们对同一个Socket实例先后调用shutdownInput和shutdownOutput方法,该Socket实例依然没有被关闭,只是该Socket既不能输出数据,也不能读取数据。

服务器端:

 1         ServerSocket ss = new ServerSocket(5555);
 2         Socket socket = ss.accept();
 3         PrintStream ps = new PrintStream(socket.getOutputStream());
 4         ps.println("服务器端:开源中国杭州论坛");
 5         ps.println("服务器端:杭州G20峰会");
 6         //关闭输出流,表明输出已经结束
 7         socket.shutdownOutput();
 8         //判断该socket是否关闭
 9         System.out.println(socket.isClosed());
10         Scanner scan = new Scanner((socket.getInputStream()));
11         while(scan.hasNextLine())
12         {
13             System.out.println(scan.nextLine());
14         }
15         scan.close();
16         socket.close();
17         ss.close();
18         
19     

 客户端:

 1         Socket s = new Socket("localhost", 5555);
 2         InputStream is = s.getInputStream();
 3         byte[] buffer = new byte[1024];
 4         int flag = 0;
 5         while(-1 != (flag = is.read(buffer,0,buffer.length)))
 6         {
 7             String str = new String(buffer,0,flag);
 8             System.out.print(str);
 9         }
10         PrintStream ps = new PrintStream(s.getOutputStream());
11         ps.println("客户端:欢迎参加开源中国论坛");
12         ps.println("客户端:欢迎参加G20峰会");
13         is.close();
14         ps.close();
15         s.close();
16     

执行结果:

   

  

  在服务器端程序中可以看到,在输出两段字符串之后,调用了shutdownOutput方法,表示输出已经结束。随即又去判断了socket是否关闭,执行的结果为false,表示socket并未关闭。

  但是在调用了这两个半关闭的方法关闭了输出输入流之后,该socket无法再次打开该输出流或者输入流。因此这种场景不适合保持持久通信状态的交互使用,只适合一站式的通信协议.例如http协议:客户端连接到服务器之后,开始发送数据,发送完成之后无须再次发送数据,只需要读取服务器响应数据即可,读取数据完毕之后,该socket连接也被关闭了。

四、基于UDP协议的网络编程

  前面介绍的socket编程都是基于TCP协议的,现在来看下基于UDP协议的编程,TCP和UDP的区别在上一章已经有过介绍。

  UDP协议的主要作用就是完成网络数据流和数据报之间的转换-----在信息的发送端,UDP协议将网络数据流封装到数据报,然后将数据报发送出去;在信息的接收端,UDP协议将数据报转换成实际数据报内容。

1、首先在UDP网络编程中没有服务器端和客户端这种说法,两个socket之间没有虚拟链路,只是接收和发送数据报文而已。

2、这里面有两个重要的类:DatagramSocket 和DatagramPacket。前者是用来发送和接收数据包的套接字,后者表示数据包,每条报文仅根据该包中的包含的信息从一台机器        路由到另一台机器。

3、DatagramSocket 的两个构造函数:

     DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。

     DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口。

     在我们下面的DEMO中,UDPServerTest类中先发送数据报,使用的是套接字的无参构造器,而UDPClientTest类中先接收数据报,必须监听某一个端口,所以使用的是套接字的有参构造器。

4、DatagramPacket:创建的时候分为接收和发送两种

      DatagramPacket(byte[] buf, int length):用来接收长度为 length 的数据包。

      DatagramPacket(byte[] buf, int length, InetAddress address, int port):用来将长度为 length 的包发送到指定主机上的指定端口号。

 1 public class UDPServerTest
 2 {
 3     public static void main(String[] args) throws IOException
 4     {
 5         DatagramSocket ds = new DatagramSocket();
 6         String str = "hello world";
 7         //构造用于发送的数据包,指定主机和端口号
 8         DatagramPacket packet = new DatagramPacket(str.getBytes(),
 9                 str.length(), InetAddress.getByName("localhost"), 5555);
10         ds.send(packet);
11         
12         //读取从客户端发送过来的响应
13         byte[] buffer = new byte[1024];
14         DatagramPacket packet2 = new DatagramPacket(buffer,buffer.length);
15         ds.receive(packet2);
16         String str2 = new String(buffer,0,packet2.getLength());
17         System.out.println(str2);
18         ds.close();
19     }
20 }
public class UDPClientTest
{public static void main(String[] args) throws Exception{DatagramSocket ds = new DatagramSocket(5555);byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);ds.receive(packet);String str = new String(buffer, 0, packet.getLength());System.out.println(str);// 接收到数据包之后,客户端返回响应回去String str2 = "welcome";DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2.length(), packet.getAddress(), packet.getPort());ds.send(packet2);ds.close();}
}

执行过程:

 

1、上面的程序中,第一步是服务器端(暂且以这种叫法来区分这两个类)创建一个UDP套接字,没有指定端口,使用的是系统分配的端口。然后构建了一个数据包,包中指定      了目标机器的ip和端口号。

2、作为客户端,创建了一个UDP套接字,并且绑定了端口,如果想要接收到服务端发送过来的报文,绑定的端口必须和服务器端发送的包中指定的端口一致。

3、客户端打印了包中的内容之后,想要返回一些内容回去。这个时候,服务器端的ip和端口号可以从之前发送过来的数据包中获取。

     DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2.length(), packet.getAddress(), packet.getPort());

4、在服务器接收数据包的时候,已经不需要再像客户端创建套接字一样去绑定端口了,因为目前监听的端口和客户端发送的包中指定的端口是一样的。

5、打印看下服务器端的ip和监听的端口号:

serverIp =/127.0.0.1;serverPort=62965

6、其中DatagramSocket的receive(DatagramPacket p)方法在接收到数据包前一直阻塞。

 

转载于:https://www.cnblogs.com/dongguacai/p/5747603.html

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

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

相关文章

在 .NET 中使用 FixedTimeEquals 应对计时攻击

计时攻击 在计算机安全中,计时攻击(Timing attack)是旁道攻击 (Side-channel attack) 的一种,而旁道攻击是根据计算机处理过程发出的信息进行分析,包括耗时,声音,功耗等…

解读大型网站系统架构的演化

解读大型网站系统架构的演化 大型网站的架构是根据业务需求不断完善的,根据不同的业务特征会做特定的设计和考虑,本文只是讲述一个常规大型网站会涉及的一些技术和手段。作者:李平来源:LEE的博客前言 一个成熟的大型网站&#xff…

【ArcGIS风暴】西北地区气象台站年均NDVI与年均气温和降水的相关性分析

在研究植被动态变化与气候的关系时,通常通过计算植被NDVI值与气温和降水的相关系数来描述相关性的大小。如下图所示,计算了西北地区分布的气象台站与气温和降水的相关性并作图可视化。 下面详细说明整个实现过程。 一、计算相关系数 1. 原理分析 通过计算年均N…

python 全解坦克大战 辅助类 附完整代码【雏形】

我正在博客之星评选,欢迎投票给我 会从投票人中抽奖机械键盘书,中了会私聊地址 投票连接是:https://bbs.csdn.net/topics/603955346 投票连接是:https://bbs.csdn.net/topics/603955346 投票连接是:https://bbs.csdn.…

vc++ mfc中拖动效果的实现 借助于CImageList

拖动是界面编程频繁使用的一个效果,在windows系统下可谓大行其道。纵观时下的应用软件几乎各个都支持各种各样拖动的效果,windows7更是把拖动做到了极致。其实说起来拖动的实现也很简单,对于有句柄的对象都可以通过MoveWindow或SetWindowPos实…

有序的Map集合--LinkedHashMap

提出问题: 在写一个dao的时候,我的需求是这个dao是一个万能的,目前的方法只有一个查询出实体类对应的表中所有的数据,通过传入的对象,利用反射获取实体类中的属性名,属性类型,利用字符串拼接获取…

yii 前后台分离及登陆验证

2019独角兽企业重金招聘Python工程师标准>>> 比较合理的做法其实是分成两个框架来布署;然而这样说法也太绝对。 事实上是针对不同系统,应采用不同的方法。如为CMS系统,则不需很复杂的权限管理,但如果有管理员与会员之分…

Kibana

2019独角兽企业重金招聘Python工程师标准>>> Kibana是一个基于浏览器页面的Elasticsearch前端展示工具。Kibana全部使用HTML语言和Javascript编写的,查询语法是基于Lucene的查询语法。允许布尔运算符、通配符和字段筛选。注意关键字要大写 全文搜索 在搜…

电脑QQ能登上,网页打不开的解决办法

打开360卫士,在功能大全里选择网络优化,断网急救箱。 可以看到DNS服务异常、浏览器配置异常,点击立即修复。

个人黑名单 抄袭耻辱墙

抄袭耻辱墙 博主抄袭文原文我爱Python数据挖掘https://blog.csdn.net/weixin_38037405/article/details/125862095https://blog.csdn.net/A757291228/article/details/117464313黄埔数据分析https://blog.csdn.net/weixin_39060517/article/details/118024847https://blog.csdn…

快速掌握 ASP.NET 身份认证框架 Identity(一)

推荐关注「码侠江湖」加星标,时刻不忘江湖事ASP.NET Core 内置了一个强大的身份认证框架 Identity,掌握它可以让我们快速开发高安全的身份认证功能,不仅如此,它还是一个基于数据库的用户管理系统,其中包含了大量的辅助…

浅谈大型web系统架构

动态应用,是相对于网站静态内容而言,是指以c/c、php、Java、perl、.net等服务器端语言开发的网络应用软件,比如论坛、网络相册、交友、BLOG等常见应用。动态应用系统通常与数据库系统、缓存系统、分布式存储系统等密不可分。   大型动态应用…

PHP: 手把手编写自己的 MVC 框架实例教程

1 什么是MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。 …

2021年复盘总结发现了C站博主缺少的赚钱之路

一、 我2021年的六大Flag 其实最开始我是不打算年终总结的,因为2021年我的十大Flag都没有完成,我说出来可能你会嘲笑我,所以我打算还是说出来吧。 这六大Flag如下: C站百万粉百篇实战文其他自媒体平台十万粉公众号一万粉财务自…

五大微信小程序开发IDE深度评测

微信小程序已经内测有一段时间了,笔者本着好奇加学习的心态写了几个小demo,虽然在MINA框架上并没有遇到太多的坑,但官方开发工具实在不敢恭维。 api提示不全,要一个个查api啊,写代码超级慢啊 很多必备的快捷键都没有&…

Maui的学习之路(2)--Mac窗体设置

Maui的学习之路今天是我开启Maui学习之路的第二天,我不是很高兴又能水一篇文章,我只能说这文章真好水。话不多说,我们进入正题,昨天解决了Windows下TitleBar以及窗体大小的问题,今天同样的问题,在Mac上又要…

ArcGIS10.8中如何获取线状、面状数据的折点,并计算折点坐标?

如下图所示为面状要素,ArcGIS10.8中如何获取线状和面状数据的折点(起点、终点、中点、端点),并计算折点的坐标(X,Y,Z,M)? 下图所示为线状(Polyline)和面状(Polygon)要素的起点、终点和折点的示意图。

[转]Cordova + Ionic in Visual Studio - 101 Tutorial [Part I]

本文转自:http://binarylies.ghost.io/cordova-ionic-in-visual-studio/ Hi everyone, I thought about lending a hand to all the people that are, as I have been recently, exploring Cordova and all its features for the first time. For the ones still tr…

【转】学会这13个原则写UI界面文案,用户才能秒懂

原文网址:http://www.niaogebiji.com/article-12011-1.html 摘要: 首先,在写UI文案之前,为了理清思路,要先搞清楚三个问题:我(设计师)想让用户做什么? – 我写文案的目的为什么要让用…

【前端就业课 第一阶段】HTML5 零基础到实战(一)基础代码结构详解

注意:手机(APP)打开,内容显示更佳,不会的私聊博主即可 想要拿代码或加入学习计划(** 博主会监督你并且教你写文章 **)的拉到最下面(PC端Web打开)加博主即可,目…