`
oywl2008
  • 浏览: 1051131 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java网络编程 使用Socket类接收和发送数据

 
阅读更多

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

在本文中,我们将讨论使用Socket类的基本步骤和方法。一般网络客户端程序在连接服务程序时要进行以下三步操作。

1.连接服务器

2.发送和接收数据

3.关闭网络连接

一、连接服务器

在客户端可以通过两种方式来连接服务器,一种是通过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语句来抛出错误。

测试正确的IP

java mysocket.MyConnection 127.0.0.1

输出结果:127.0.0.1已经连接成功!

测试错误的IP

java mysocket.MyConnection 10.10.10.10

输出结果:错误信息:Connection timed out: connect

注:10.10.10.10是一个并不存在的IP,如果这个IP在你的网络中存在,请使用其它的不存在的IP。

测试正确的域名

java mysocket.MyConnection www.ptpress.com.cn

输出结果:www.ptpress.com.cn已经连接成功!

测试错误的域名

java mysocket.MyConnection www.ptpress1.com.cn

输出结果:错误信息:www.ptpress1.com.cn

使用Socket类连接服务器可以判断一台主机有哪些端口被打开。下面的代码是一个扫描本机有哪些端口被打开的程序。

package mysocket;

import java.net.*;

public class MyConnection1 extends Thread

{

private int minPort, maxPort;

public MyConnection1(int minPort, int maxPort)

{

this.minPort = minPort;

this.maxPort = maxPort;

}

public void run()

{

for (int i = minPort; i <= maxPort; i++)

{

try

{

Socket socket = new Socket("127.0.0.1", i);

System.out.println(String.valueOf(i) + ":ok");

socket.close();

}

catch (Exception e)

{

}

}

}

public static void main(String[] args)

{

int minPort = Integer.parseInt(args[0]), maxPort = Integer

.parseInt(args[1]);

int threadCount = Integer.parseInt(args[2]);

int portIncrement = ((maxPort - minPort + 1) / threadCount)

+ (((maxPort - minPort + 1) % threadCount) == 0 ? 0 : 1);

MyConnection1[] instances = new MyConnection1[threadCount];

for (int i = 0; i < threadCount; i++)

{

instances[i] = new MyConnection1(minPort + portIncrement * i, minPort

+ portIncrement - 1 + portIncrement * i);

instances[i].start();

}

}

}

上面代码通过一个指定的端口范围(如1至1000),并且利用多线程将这个端口范围分成不同的段进行扫描,这样可以大大提高扫描的效率。

可通过如下命令行去运行例程4-2。

java mysocket.MyConnection1 1000 3000 20

 

 

 

 

二、发送和接收数据

 

在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种:

1. 直接调用Socket类的close方法。

2. 只要Socket类的InputStream和OutputStream有一个关闭,网络连接自动关闭(必须通过调用InputStream和OutputStream的close方法关闭流,才能使网络可爱接自动关闭)。

3. 在程序退出时网络连接自动关闭。

4. 将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对象的状态。

 

 

 

http://tech.ccidnet.com/art/3539/20090514/1768013_1.html

 

 

<!--638广告位2-->

分享到:
评论

相关推荐

    使用Socket类接收和发送数据

    ### 使用Socket类接收和发送数据 #### 知识点概览 在计算机网络通信中,Socket编程是一种常用的技术手段,它允许程序通过网络进行通信。本文将深入探讨如何使用Java中的`Socket`类来实现数据的接收与发送,并提供...

    利用socket连续发送与连续接收数据

    在IT领域,网络编程是不可或缺的一部分,而Socket编程则是实现网络...连续发送和接收数据的场景在许多应用中都很常见,比如文件传输、在线聊天等。通过理解和掌握Socket编程,开发者可以构建出高效且可靠的网络应用。

    Java网络编程实验报告.pdf

    Socket 类提供了多种构造方法和方法,用于创建客户端的 Socket,连接服务器端的 Socket,发送和接收数据等。 知识点5:DataInputStream 和 DataOutputStream 类 DataInputStream 和 DataOutputStream 类是Java ...

    Java网络编程(socket---网上广播).rar_Java 网络_Socket网络编程_java socket _ja

    客户端则使用`Socket`类来建立与服务器的连接,并通过这个连接发送和接收数据。"mclient.java"文件应包含了客户端的实现,包括创建`Socket`对象,指定服务器的IP地址和端口号,以及数据的发送和接收。 在Java网络...

    Java Socket发送和接收的例子

    在这个例子中,我们将探讨如何使用Java Socket进行数据的发送和接收。Socket在Java中被封装在`java.net.Socket`和`java.net.ServerSocket`类中,分别用于客户端和服务器端的通信。 首先,我们从服务器端开始。在...

    JAVA Socket 网络编程教程

    一个简单的聊天室系统就是一个使用Java Socket实现的典型例子,服务器端接收多个客户端的连接请求,每个客户端都可以发送消息给其他所有在线的客户端。 十、总结 Java Socket编程是构建网络应用的基础,掌握其原理...

    java网络编程socket编程等

    3. DatagramSocket和DatagramPacket:用于UDP通信,DatagramSocket是发送和接收UDP数据包的类,DatagramPacket则是数据包的封装对象。 二、TCP编程 1. TCP连接:TCP是一种面向连接的、可靠的传输层协议。在通信前,...

    Android开发,Socket Client端和Socket Server端数据发送和接收

    在Android开发中,Socket通信是实现设备间网络通信的一种常见方式...以上就是关于Android开发中Socket Client端和Socket Server端数据发送和接收的核心知识点。理解并掌握这些内容,将有助于构建稳定的跨设备通信系统。

    基于Socket的java网络编程

    Java网络编程的核心是基于Socket进行通信,Socket是TCP/IP协议栈的一种实现,它允许两个网络节点(通常是客户端和服务器)通过TCP或UDP进行数据交换。Socket接口为应用程序提供了低级别的网络通信控制,允许开发者...

    Java网络编程-Socket-文件传输小案例

    在Java编程领域,网络编程是不可或缺的一部分,而Socket通信则是实现网络数据传输的基础。本案例主要探讨了如何使用Java的Socket API进行简单的文件传输。在这个过程中,我们将涉及到以下几个关键知识点: 1. **...

    Java网络编程,Socket通信开发

    通过这两个类,我们可以创建连接、发送和接收数据,并管理连接状态。例如,`Socket`的`getOutputStream()`方法用于获取输出流,从而可以向远程主机写入数据;`Socket`的`getInputStream()`方法用于获取输入流,读取...

    java网络编程socket可视化

    在本项目"java网络编程socket可视化"中,我们将探讨如何使用Java Socket API创建一个简单的服务器,以及与其交互的客户端应用,同时实现数据的可视化展示。 首先,我们需要理解Socket的工作原理。Socket是网络上的...

    java网络编程 socket

    通过阅读《Java网络编程文档教材》和《Java基础三步学会JavaSocket编程》,你可以更深入地了解Java Socket编程的细节和实践技巧。理论结合实践,才能真正掌握这一技术。在实际开发中,不断优化和调试,才能编写出...

    Java网络编程 Socket编程

    Java网络编程是使用Java语言编写网络应用程序的过程,而Socket编程是实现Java网络编程的一种重要手段。本篇将详细解析Java网络编程中Socket编程的关键知识点,包括TCP实现、多线程在Socket编程中的应用、UDP程序的...

    Java网络socket编程详解

    Java网络socket编程是Java编程语言在网络编程中的一项核心技术,主要涉及到网络通信的两个基本概念:客户端(Client)和服务器(Server)。在Java中实现网络通信,主要依赖于Socket编程模型,尤其是基于TCP/IP协议的...

    总结java_socket编程.doc

    发送方和接收方的成对的两个Socket之间必须建立连接,以便在TCP协议的基础上进行通信。 UDP 协议 UDP协议是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或...

    java网络编程第四版pdf

    这些内容详细阐述了如何利用Java进行网络通信,包括建立连接、发送和接收数据、处理异常以及优化网络性能。 总的来说,《Java网络编程(第四版)》是一本全面而实用的教程,适合有一定Java基础的开发者学习。它不仅...

    java网络编程 socket的TCP应用编程

    - 获取Socket对象的输入输出流,用于发送和接收数据。 5. **源码分析**: - 服务端代码通常包含一个无限循环,不断调用accept()接收新连接,为每个连接创建新的线程处理。 - 客户端代码通常包括建立连接,发送...

    Java网络编程socket通讯简单封装(使用多线程)_20170808_LK

    在这个主题中,“Java网络编程socket通讯简单封装(使用多线程)”着重讨论了如何在Java中使用Socket进行基本的网络通信,并通过多线程提升并发处理能力。 首先,Socket在Java中的实现主要依赖于`java.net.Socket`和`...

Global site tag (gtag.js) - Google Analytics