`

android网络编程(六)Socket

阅读更多
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 com.amaker.socker;

import java.net.Socket;

public class MyConnection {
	public static void main(String[] args){
		String[] strs = {"127.0.0.1"};
		connectTest(strs);
	}
	public static void connectTest(String[] strs){
		try{
			if (strs.length > 0){
				Socket socket = new Socket(strs[0], 80);
				System.out.println(strs[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 com.amaker.socker;

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),并且利用多线程将这个端口范围分成不同的段进行扫描,这样可以大大提高扫描的效率。




二、发送和接收数据

在Socket类中最重要的两个方法就是getInputStream和getOutputStream。这两个方法分别用来得到用于读取和写入数据的InputStream和OutputStream对象。在这里的InputStream读取的是服务器程序向客户端发送过来的数据,而OutputStream是客户端要向服务端程序发送的数据。


在编写实际的网络客户端程序时,是使用getInputStream,还是使用getOutputStream,以及先使用谁后使用谁由具体的应用决定。如通过连接邮电出版社网站(www.ptpress.com.cn)的80端口(一般为HTTP协议所使用的默认端口),并且发送一个字符串,最后再读取从www.ptpress.com.cn返回的信息。

package com.amaker.socker;

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 com.amaker.socker;

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 com.amaker.socker;

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对象的状态。 
	 */
}
分享到:
评论

相关推荐

    Android网络编程基于socket的通信

    Android中,直接采用Socket通信应该是我们遇到的最低级的网络运用。

    Android网络编程-聊天室开发

    本资料详细介绍了如何在Android平台上使用Socket进行网络编程,并通过具体的示例代码展示了聊天室的开发过程,包括服务器端和Android客户端的开发。 #### 二、服务器端程序开发 服务器端程序通常运行在一台PC机上...

    android socket 编程实例

    在Android平台上进行网络通信时,Socket编程是一种常见且重要的技术,它允许设备通过TCP或UDP协议与其他设备或服务器进行双向数据传输。在这个实例中,我们将深入探讨如何在Android客户端和Java服务器端实现Socket...

    android socket编程实例

    android socket编程实例

    Android Socket编程实践

    Android Socket编程实践

    android 网络编程详解代码第7章(android的Socket编程)

    本章重点讲解的是Android的Socket编程,这是网络通信的基础,它允许设备通过Internet进行双向通信。Socket编程提供了低级别的接口,使得开发者可以直接控制数据传输,实现高效、可靠的数据交换。 首先,让我们理解...

    android_Socket编程

    Android Socket编程是移动应用开发中实现设备间网络通信的关键技术。Socket,又称套接字,是一种网络编程接口,允许应用程序通过网络与其他设备上的应用程序进行数据交换。本篇将深入探讨Socket的基本概念、通信模型...

    android 网络编程 客户端完整代码 socket http

    本文将深入探讨Android中基于Socket和HTTP的网络编程,包括它们的概念、实现方式以及如何构建一个完整的客户端代码。 1. Socket(套接字)网络编程: Socket是网络通信的基础,它提供了进程间通信的能力,使得运行...

    Android中的Socket编程

    在Android应用开发中,Socket编程是实现设备间通信的重要手段,尤其在构建网络服务、实时数据传输等场景中不可或缺。本教程将引导初学者逐步理解并掌握Android中的Socket编程技术。 首先,Socket在计算机网络中被...

    android socket tcp client 安卓socket编程

    在Android平台上进行网络通信时,Socket通信是一种常见的方式,它基于TCP/IP协议,提供可靠的、面向连接的数据传输。本篇文章将深入探讨如何在Android中实现一个TCP客户端(Socket客户端),以便与服务器进行双向...

    MFC socket网络编程

    虽然本知识点主要针对PC端,但值得注意的是,Android网络编程同样可以使用Socket,而且原理和方法与PC端类似。移动设备通过Socket连接到服务器,可以实现各种网络功能。 ### 结论 MFC Socket网络编程是一种较为...

    Android Socket 编程案例

    无论是Android客户端还是Java服务器端,Socket编程中都可能出现各种异常,如网络中断、连接超时等。因此,必须捕获并适当地处理这些异常,确保程序的健壮性。 5. **性能优化**: 在实际应用中,通常会使用多线程...

    Android-netty和socket通信的demo

    本示例“Android-netty和socket通信的demo”将展示如何在Android平台上利用Netty进行网络通信,与传统的Socket编程相结合,实现更加灵活和高效的通信机制。 首先,理解Netty的基本概念是非常重要的。Netty是一个...

    Android Socket编程客户端服务器端源码

    在Android开发中,Socket编程是实现设备间通信的重要手段,特别是在构建网络应用时。本教程将深入探讨Android Socket编程的基本概念、客户端与服务器端的实现以及相关源码解析。 一、Socket基本概念 Socket,也被...

    Android中的Socket编程(包含服务端代码)

    在Android开发中,Socket编程是实现设备间通信的重要手段,特别是在构建网络应用程序时。本教程将深入探讨如何在Android客户端和Java服务端之间利用Socket进行数据传输。首先,我们需要了解Socket的基本概念。Socket...

    android Socket网络编程

    此demo包括两个moudle,一个Server,另一个Client,Server是个纯java文件,可以放到随便什么地方去执行,只要有JDK;Client是Android App。运行时注意修改IP为自己的IP

    Android Socket网络编程.pdf

    《Android Socket网络编程》 Android Socket网络编程是Android应用程序中实现客户端与服务器间通信的关键技术。在Android平台上,Socket主要用于客户端应用,与Java标准Socket编程类似,但有一些关键区别,这些差异...

    计算机网络编程socket客户端与服务器通讯

    ### 计算机网络编程socket客户端与服务器通讯 #### 概述 计算机网络编程是现代互联网技术的基础之一,其中socket编程是一种重要的实现方式。本文将详细介绍一个基于Android客户端与服务器之间进行socket通信的设计...

    Android socket编程1

    在Android开发中,Socket编程是实现设备间通信的重要手段,特别是在构建网络应用和服务时。"Android socket编程1"是一个入门级示例,旨在教授如何在Android平台上使用Socket进行网络通信。这个示例程序中,开发者...

Global site tag (gtag.js) - Google Analytics