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] + "已连接成功!"); } else system.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,以及先使用谁后使用谁由具体的应用决定。如通过连接邮电出版社网站()的80端口(一般为http协议所使用的默认端口),并且发送一个字符串,最后再读取从返回的信息。
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 + "处于连接状态!"); else system.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对象的状态。
希望本文所述对你有所帮助,java使用socket类接收和发送数据内容就给大家介绍到这里了。希望大家继续关注我们的网站!想要学习java可以继续关注本站。
上一篇: Java爬虫实战抓取一个网站上的全部链接
下一篇: Spring测试 其实很简单
推荐阅读
-
java使用Socket类接收和发送数据
-
Java使用JavaMail API发送和接收邮件的代码示例
-
Java使用JavaMail API发送和接收邮件的代码示例
-
java使用Socket类接收和发送数据
-
Java Socket通信(一)之客户端程序 发送和接收数据
-
Java Socket通信(一)之客户端程序 发送和接收数据
-
java使用jdbc连接数据库工具类和jdbc连接mysql数据示例
-
java使用jdbc连接数据库工具类和jdbc连接mysql数据示例
-
JavaEE基础day02 1.定义Java中的变量 四类八种 2.变量定义和使用的注意事项 3.数据类型的转换、强制数据类型转换4.算数运算符、比较运算符、逻辑运算符、赋值运算符、三元运算符
-
C#使用Socket发送和接收TCP数据实例