java使用Socket类接收和发送数据

java使用Socket类接收和发送数据

网络应用分为客户端和服务端两部分,而Socket类是负责处理客户端通信的Java类。通过这个类可以连接到指定IP或域名的服务器上,并且可以和服务器互相发送和接受数据。在本文及后面的数篇文章中将详细讨论Socket类的使用,内容包括Socket类基础、各式各样的连接方式、get和set方法、连接过程中的超时以及关闭网络连接等。
在本文中,我们将讨论使用Socket类的基本步骤和方法。一般网络客户端程序在连接服务程序时要进行以下三步操作。

  • 连接服务器
  • 发送和接收数据
  • 关闭网络连接

一、连接服务器

在客户端可以通过两种方式来连接服务器,一种是通过IP的方式来连接服务器,而另外一种是通过域名方式来连接服务器。
其实这两种方式从本质上来看是一种方式。在底层客户端都是通过IP来连接服务器的,但这两种方式有一定的差异,如果通过IP方式来连接服务端程序,客户端只简单地根据IP进行连接,如果通过域名来连接服务器,客户端必须通过DNS将域名解析成IP,然后再根据这个IP来进行连接。
在很多程序设计语言或开发工具中(如C/C++、Delphi)使用域名方式连接服务器时必须自己先将域名解析成IP,然后再通过IP进行连接,而在Java中已经将域名解析功能包含在了Socket类中,因此,我们只需象使用IP一样使用域名即可。
通过Socket类连接服务器程序最常用的方法就是通过Socket类的构造函数将IP或域名以及端口号作为参数传入Socket类中。Socket类的构造函数有很多重载形式,在这一节只讨论其中最常用的一种形式:public Socket(String host, int port)。从这个构造函数的定义来看,只需要将IP或域名以及端口号直接传入构造函数即可。下面的代码是一个连接服务端程序的例子程序:

package mysocket; 
import java.net.*; 
public class MyConnection
{public static void main(String[] args){try{if (args.length > 0){Socket socket = new Socket(args[0], 80);System.out.println(args[0] + "已连接成功!");}elseSystem.out.println("请指定IP或域名!");}catch (Exception e){System.err.println("错误信息:" + e.getMessage());}}
}

在上面的中,通过命令行参数将IP或域名传入程序,然后通过Socket socket = new Socket(args[0], 80)连接通过命令行参数所指定的IP或域名的80端口。由于Socket类的构造函数在定义时使用了throws,因此,在调用Socket类的构造函数时,必须使用try…catch语句来捕捉错误,或者对main函数使用throws语句来抛出错误。
使用Socket类连接服务器可以判断一台主机有哪些端口被打开。下面的代码是一个扫描本机有哪些端口被打开的程序。

二、发送和接收数据

在Socket类中最重要的两个方法就是getInputStream和getOutputStream。这两个方法分别用来得到用于读取和写入数据的InputStream和OutputStream对象。在这里的InputStream读取的是服务器程序向客户端发送过来的数据,而OutputStream是客户端要向服务端程序发送的数据。
在编写实际的网络客户端程序时,是使用getInputStream,还是使用getOutputStream,以及先使用谁后使用谁由具体的应用决定。如通过连接邮电出版社网站(www.ptpress.com.cn)的80端口(一般为HTTP协议所使用的默认端口),并且发送一个字符串,最后再读取从www.ptpress.com.cn返回的信息。

package mysocket;
import java.net.*;
import java.io.*; 
public class MyConnection2
{public static void main(String[] args) throws Exception{Socket socket = new Socket("www.ptpress.com.cn", 80);// 向服务端程序发送数据OutputStream ops = socket.getOutputStream();    OutputStreamWriter opsw = new OutputStreamWriter(ops);BufferedWriter bw = new BufferedWriter(opsw);bw.write("hello world\r\n\r\n");bw.flush();// 从服务端程序接收数据InputStream ips = socket.getInputStream();InputStreamReader ipsr = new InputStreamReader(ips);BufferedReader br = new BufferedReader(ipsr);String s = "";    while((s = br.readLine()) != null)System.out.println(s);    socket.close();}
}

在编写上面代码时要注意如下两点:

  1. 为了提高数据传输的效率,Socket类并没有在每次调用write方法后都进行数据传输,而是将这些要传输的数据写到一个缓冲区里(默认是8192个字节),然后通过flush方法将这个缓冲区里的数据一起发送出去,因此,bw.flush();是必须的。
  2. 在发送字符串时之所以在Hello World后加上 “\r\n\r\n”,这是因为HTTP协议头是以“\r\n\r\n”作为结束标志(HTTP协议的详细内容将在以后讲解),因此,通过在发送字符串后加入“\r\n\r\n”,可以使服务端程序认为HTTP头已经结束,可以处理了。如果不加“\r\n\r\n”,那么服务端程序将一直等待HTTP头的结束,也就是“\r\n\r\n”。如果是这样,服务端程序就不会向客户端发送响应信息,而br.readLine()将因无法读以响应信息面被阻塞,直到连接超时。

三、关闭网络连接

到现在为止,我们对Socket类的基本使用方法已经有了初步的了解,但在Socket类处理完数据后,最合理的收尾方法是使用Socket类的close方法关闭网络连接。虽然在中已经使用了close方法,但使网络连接关闭的方法不仅仅只有close方法,下面就让我们看看Java在什么情况下可以使网络连接关闭。
可以引起网络连接关闭的情况有以下4种:

  • 直接调用Socket类的close方法。
  • 只要Socket类的InputStream和OutputStream有一个关闭,网络连接自动关闭(必须通过调用InputStream和OutputStream的close方法关闭流,才能使网络可爱接自动关闭)。
  • 在程序退出时网络连接自动关闭。
  • 将Socket对象设为null或未关闭最使用new Socket(…)建立新对象后,由JVM的垃圾回收器回收为Socket对象分配的内存空间后自动关闭网络连接。

虽然这4种方法都可以达到同样的目的,但一个健壮的网络程序最好使用第1种或第2种方法关闭网络连接。这是因为第3种和第4种方法一般并不会马上关闭网络连接,如果是这样的话,对于某些应用程序,将会遗留大量无用的网络连接,这些网络连接会占用大量的系统资源。
在Socket对象被关闭后,我们可以通过isClosed方法来判断某个Socket对象是否处于关闭状态。然而使用isClosed方法所返回的只是Socket对象的当前状态,也就是说,不管Socket对象是否曾经连接成功过,只要处于关闭状态,isClosde就返回true。如果只是建立一个未连接的Socket对象,isClose也同样返回true。如下面的代码将输出false。

Socket socket = new Socket();
System.out.println(socket.isClosed());

除了isClose方法,Socket类还有一个isConnected方法来判断Socket对象是否连接成功。看到这个名字,也许读者会产生误解。其实isConnected方法所判断的并不是Socket对象的当前连接状态,而是Socket对象是否曾经连接成功过,如果成功连接过,即使现在isClose返回true,isConnected仍然返回true。因此,要判断当前的Socket对象是否处于连接状态,必须同时使用isClose和isConnected方法,即只有当isClose返回false,isConnected返回true的时候Socket对象才处于连接状态。下面的代码演示了上述Socket对象的各种状态的产生过程。

package mysocket;
import java.net.*; 
public class MyCloseConnection
{public static void printState(Socket socket, String name){System.out.println(name + ".isClosed():" + socket.isClosed());System.out.println(name + ".isConnected():" + socket.isConnected());if (socket.isClosed() == false && socket.isConnected() == true)System.out.println(name + "处于连接状态!");elseSystem.out.println(name + "处于非连接状态!");System.out.println();}public static void main(String[] args) throws Exception{Socket socket1 = null, socket2 = null;socket1 = new Socket("www.ptpress.com.cn", 80);printState(socket1, "socket1");socket1.getOutputStream().close();printState(socket1, "socket1");socket2 = new Socket();printState(socket2, "socket2");socket2.close();printState(socket2, "socket2");}
}

运行上面的代码后,将有如下的输出结果:
socket1.isClosed():false
socket1.isConnected():true
socket1处于连接状态!
socket1.isClosed():true
socket1.isConnected():true
socket1处于非连接状态!
socket2.isClosed():false
socket2.isConnected():false
socket2处于非连接状态!
socket2.isClosed():true
socket2.isConnected():false
socket2处于非连接状态!
从输出结果可以看出,在socket1的OutputStream关闭后,socket1也自动关闭了。而在上面的代码我们可以看出,对于一个并未连接到服务端的Socket对象socket2,它的isClosed方法为false,而要想让socket2的isClosed方法返回true,必须使用socket2.close显示地调用close方法。

虽然在大多数的时候可以直接使用Socket类或输入输出流的close方法关闭网络连接,但有时我们只希望关闭OutputStream或InputStream,而在关闭输入输出流的同时,并不关闭网络连接。这就需要用到Socket类的另外两个方法:shutdownInput和shutdownOutput,这两个方法只关闭相应的输入、输出流,而它们并没有同时关闭网络连接的功能。和isClosed、isConnected方法一样,Socket类也提供了两个方法来判断Socket对象的输入、输出流是否被关闭,这两个方法是isInputShutdown()和isOutputShutdown()。下面的代码演示了只关闭输入、输出流的过程:

package mysocket;
import java.net.*; 
public class MyCloseConnection1
{public static void printState(Socket socket){System.out.println("isInputShutdown:" + socket.isInputShutdown());System.out.println("isOutputShutdown:" + socket.isOutputShutdown());System.out.println("isClosed:" + socket.isClosed());System.out.println();}public static void main(String[] args) throws Exception{Socket socket = new Socket("www.ptpress.com.cn", 80);printState(socket);socket.shutdownInput();printState(socket);socket.shutdownOutput();printState(socket);}
}

在运行上面的代后,将得到如下的输出结果:
isInputShutdown:false
isOutputShutdown:false
isClosed:false
isInputShutdown:true
isOutputShutdown:false
isClosed:false
isInputShutdown:true
isOutputShutdown:true
isClosed:false
从输出结果可以看出,isClosed方法一直返回false,因此,可以肯定,shutdownInput和shutdownOutput并不影响Socket对象的状态。

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

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

相关文章

Docker Swarm compose 文件 depends_on 属性

Swarm 部署时候如果需要管理应用之间的启动先后顺序,则可以使用 services.depends_on 属性进行指定,例如 services:eureka-service:......depends_on:- config-service......

Java 单例模式:懒加载(延迟加载)和即时加载

Java 单例模式:懒加载(延迟加载)和即时加载 引言 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制(或懒加载、延时加载),也就是说只有当使用到这…

递推算法之滚动数组思维方式

概述 在算法的最终结果只用到本层与上一层的结果时, 可以使用滚动数组思想。 简单的理解就是每次都使用固定的几个存储空间达到压缩节省存储空间的作用, 主要用在递推算法中。示例1: 爬楼梯问题 假设你正在爬楼梯。需要 n 阶你才能到达楼顶…

Java创建并执行线程的四种方法

Java创建并执行线程的四种方法 java里面创建线程有四种方式: 无返回: 实现Runnable接口,重写run();继承Thread类,重写run(); 有返回:实现Callable接口,重写call(),利用FutureTask包装Callable&#xff0c…

idea中svn的更新、检出、提交操作

一、首先集成svn到idea 点击号连接svn仓库地址 等待代码下载完毕后就可以对代码进行update,commit操作了 更新操作方法一:项目上右键 方法二:点击快捷图标 方法三: 代码提交 方法一 方法二: 方法三: 会跳出窗口: 然后点击Commit 如果检测代码有错误会询问你是否要处理,一般确定…

判断链表是否相交并找出交点

问题概述 单链表定义如下: public class ListNode {int val;ListNode next;ListNode(int x) {val x;next null;}}编写程序, 找出两个链表的交点。 如图所示,链表 A 和链表 B 在节点 8 处相交。 算法思路 首先确定一个事情: …

socket和http区别有哪些

socket和http区别有哪些 1、socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉; 2、http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉。 socket和http区别&…

Spring Bean 的生命周期

概述 Spring 启动,扫描指定的包路径,查找需要被 Spring 管理的 bean构造 BeanDefinition 对象实例化 bean,如果有多个构造方法,则需要推断构造方法,确定好构造方法后,进行实例化得到一个对象进行 bean 的属…

兄弟3150cdn更换硒鼓_耗材知多点:一体式硒鼓及分离式硒鼓

相信第一次接触硒鼓的小伙伴们,会比较诧异为什么有些硒鼓可以直接装机使用,而有些硒鼓,却需要两个部件组合起来或分别装机才能正常使用。今天就带大家来了解一下什么是一体式硒鼓,什么又是分离式硒鼓。①一体式硒鼓:以…

Java IO流之PrintStream分析

简介 PrintStream继承了FilterOutputStream.是"装饰类"的一种,所以属于字节流体系中(与PrintStream相似的流PrintWriter继承于Writer,属于字符流体系中),为其他的输出流添加功能.使它们能够方便打印各种数据值的表示形式.此外,值得注意的是: 与其他流不同的是,Prin…

bs4爬取的时候有两个标签相同_10分钟用Python爬取最近很火的复联4影评

《复仇者联盟4:终局之战》已经上映快三个星期了,全球票房破24亿美元,国内票房破40亿人民币。虽然现在热度逐渐下降,但是我们还是恬不知耻地来蹭一蹭热度。上映伊始《复联4》的豆瓣评分曾破了9分。后来持续走低,现在《复…

RabbitMQ 基本概念与高级特性

文章目录1. 什么是消息队列1.1 消息队列概述1.2 使用消息队列的优势1.3 使用消息队列的劣势1.4 常见的消息队列产品对比2. RabbitMQ 基本概念2.1 RabbitMQ 概述2.2 RabbitMQ 的概念模型2.2.1 Message2.2.2 Publisher2.2.3 Exchange2.2.4 Binding2.2.5 Queue2.2.6 Connection2.2…

HTTP 和 SOCKET 的区别

HTTP 和 SOCKET 的区别 要弄明白 http 和 socket 首先要熟悉网络七层:物 数 网 传 会 表 应,如图1 如图1 HTTP 协议:超文本传输协议,对应于应用层,用于如何封装数据. TCP/UDP 协议:传输控制协议,对应于传输层&…

java 8进制串转中文_为什么不能用中文进行编程?而英文就可以

前些天大雄无意间听见几个线下班小伙伴说真的是无(te)意(di)的“我要补英文”“对,英文真的很重要”“如果编码用中文就好了”...听见这大雄就不淡定了中文代码小伙伴确定能够搞懂??首先我们大概的看一下中文编码:你以为会写中文写…

Java 父子类方法调用顺序

概述 在 Java 的多态中,有个结论可以直接引用: 对象类型看左边静态方法和成员变量看左边成员方法,编译看左边,运行看右边(子类可能重写)如果有多个匹配的方法可以调用,优先调用参数最匹配的一个 调用顺序…

TCP/IP,HTTP,Socket的区别与联系

TCP/IP,HTTP,Socket的区别与联系 网络七层:物数网传会表应.分别为物理层,数据链路层,网络层,传输层,会话层,表示层,应用层.其中,底层三层:物理层,数据链路层,网络层是网络工程师研究的对象,而其它四层,是用户面向和关心的问题. http协议:超文本传输协议, 对应于应用层. tcp协议…

MATLAB学习笔记(一)求解三阶微分方程

一、求解三阶微分方程 对于多变量三阶微分方程求解问题,这里介绍一种求解方法。 例题如下: 对于以上方程,给定边界条件,,,,,。求解和的表达式。 二、解题步骤 (1&…

Docker exec 命令执行出错, 显示 the input device is not aTTY 的解决办法

问题描述 在使用 docker exec 命令进入容器时,发现报错信息如下: the input device is not a TTY. If you are using mintty, try prefixing the command with winpty解决办法 这是因为命令行权限不足导致的,解决办法就是提升权限 Windo…

JAVA 判断Socket 远程端是否断开连接

JAVA 判断Socket 远程端是否断开连接 最近在做项目的时候,遇到这样一个问题,如何判断 Socket 远程端连接是否关闭,如果关闭的话,就要重建连接Socket的类提供了一些已经封装好的方法, 如 isClosed()、isConnected()、i…

axure 内部框架内容下滑_Axure教程:转盘抽奖交互原型

本文跟大家分享,如何使用axure制作转盘抽奖交互原型,不带登录流程。效果如下:抽奖流程一、主要内容(1)主要元件:动态面板(2)重点:旋转交互、随机函数、触发动作。(3)难点:通过停止位置判断抽奖结果(4)涉及函…