Java网络编程-初识Socket
来源:互联网 发布:淘宝哪里申请换货 编辑:程序博客网 时间:2024/04/29 03:59
原文:http://www.sunnyang.com/410.html
Socket套接字计算机网络通信的基本技术之一。大多数基于网络的软件,如浏览器、即时通讯工具(QQ)或者P2P下载(迅雷)都是基于Socket实现的。本文介绍了Socket的一些基础知识点,对UDP协议没有过多的涉及,简要分析了Socket和HTTP.
Socket介绍
在了解Socket之前,首先要了解什么是客户端/服务器(client/server)模式。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如ORACLE、SYBASE、InfORMix或 SQL Server。客户端需要安装专用的客户端软件。客户端与服务器要进行通信,提供它们之间互相通信的接口就是Socket,所以说Socket本身并不是一种协议,而是基于一组协议设计而提供的对外操作的接口。
Socket可以说是对TCP/IP协议的封装和应用(程序员层面上),但是它也适用于其它协议如UDP协议,Socket 是一种应用接口, TCP/IP 是网络传输协议,虽然接口相同, 但是不同的协议会有不同的服务性质。创建Socket 连接时,可以指定使用的传输层协议,Socket 可以支持不同的传输层协议(TCP 或UDP ),当使用TCP 协议进行连接时,该Socket 连接就是一个TCP 连接。因此也可以说Socket跟TCP/IP协议没有必然的联系。Socket的出现只是可以更方便的使用TCP/IP 协议栈而已。
Java语言中Socket通信机制采用了IO流操作模型。首先通信的双方,客户端和服务器需要建立Socket连接;之后双方都有各自的Socket对象。该Socket对象包含两个流:一个是输入流InputStream,其作用是接收数据;另一个是输出流OutputStream,作用是向外发送数据。
Java为TCP协议提供了两个类:Socket类和ServerSocket类。一个Socket实例代表了TCP连接的一端。一个TCP连接(TCP connection)是一条抽象的双向信道,两端分别由IP地址和端口号确定。在开始通信之前,要建立一个TCP连接,这需要先由客户端TCP向服务器端TCP发送连接请求。ServerSocket实例则监听TCP连接请求,并为每个请求创建新的Socket实例。也就是说,服务器端要同时处理ServerSocket实例和Socket实例,而客户端只需要使用Socket实例。
Socket与HTTP区别
网络七层协议物理层、数据链路层、网络层、传输层、回话层、表示层和应用层,Socket位于传输层,而HTTP位于应用层。HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。
由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即使不需要获
得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。
很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。
HTTP协议手机都支持,Socket不一定(Android对于WebSocket的支持很差)。
HTTP只能是一问一答(即以request/response 的方式连网收发信息), 而Socket可以双向通讯( 定位到某一URL 后, 就可以双方收发信息, 无需request/response) 。
Socket 可能会被防火墙屏蔽, 但HTTP可以穿越防火墙。
HTTP 是基于Socket 通信的子协议, Socket 收发信息自由, 协议都可由使用者定义。 HTTP 在Socket 基础上做了协议规范, 通信只能按照特定的格式去做, 用户可在HTTP 上做自己的子协议, 如网页浏览,webservice,soap等
Socket编程示例
交互过程
Socket类
Socket常用的构造方法如下:
Socket(InetAddress address, int port)throws UnknownHostException, IOExceptionSocket(String host, int port)throws UnknownHostException, IOException
如果失败会抛出IOException错误。如果成功,则返回Socket对象。InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例。
host一般为客户端的IP地址,port就是服务器端用来监听请求的端口,也即是服务端的端口。在选择端口时,需要注意一点,就是0~1023这些端口都已经被系统预留了。这些端口为一些常用的服务所使用,比如邮件,FTP和HTTP。当你在编写服务器端的代码,选择端口时,请选择一个大于1023的端口。
当Socket实例化完成,就表示与服务器建立好了连接。但是数据的发送和接收还需要从Socket对象中获取输入流InputStream和输出流OutputStream,IO流的获取主要通过以下方法:
public InputStream getInputStream()throws IOExceptionpublic OutputStream getOutputStream()throws IOException
由上面可以知道,客户端操作主要包括两个步骤:
建立连接;
进行流的读写操作。
public class TCPClient { private static int PORT=1001; private static String HOST="127.0.0.1"; public static void main(String[] args) { String str="hello world!"; try { //建立连接 Socket client=new Socket(HOST, PORT); OutputStream os=client.getOutputStream(); InputStream is=client.getInputStream(); //IO流写入操作 os.write(str.getBytes()); byte buffer[]=new byte[1024]; int len=-1; //IO流的读取操作 while((len=is.read(buffer))!=-1){ System.out.println(new String(buffer, 0, len)); } os.close(); is.close(); }catch (Exception e) { e.printStackTrace(); } }}
ServerSocket类
上述客户端仅仅表示通信的一方,若要真正完成通信,还需要相应的、能根据客户的请求作出相应的服务器程序。服务器这一端的功能实现就是通过ServerSocket实现的,ServerSocket常用的构造方法如下:
ServerSocket(int port)throws IOException
该构造方法创建一个ServerSocket对象,并绑定到所指定的端口port上面。ServerSocket对象一旦建立,就可以完成其监听端口和等待连接的功能,所采用的实例方法是:
public Socket accept()throws IOException
上述该方法是一个阻塞方法,阻塞的含义是其将一直处于等待状态,直到有连接请求才从方法中返回。方法的返回值是一个Socket对象,服务端就是通过该对象与客户端进行通信的。
服务端的操作一般分为以下三个步骤:
监听端口
接收连接
进行流的读写操作
public class TCPServer { private static int PORT=1001; public static void main(String[] args) { try { //监听端口 ServerSocket server=new ServerSocket(PORT); while(true){ //接收连接 Socket client=server.accept(); //流的读写操作 InputStream is=client.getInputStream(); OutputStream os=client.getOutputStream(); byte buffer[]=new byte[1024]; int len=-1; while((len=is.read(buffer))!=-1){ System.out.println(new String(buffer, 0, len)); os.write("tcp server".getBytes()); } } } catch (IOException e) { e.printStackTrace(); } }
多线程ServerSocket
在上面的ServerSocket示例代码中,我们采用的是一种顺序处理方式,当有多个客户向服务器发送请求时,服务器是一个一个轮流处理得;若是服务器对每个请求都有较为复杂的处理,就会导致某些客户有较长的等待时间。这非常类似于在 银行排队等候处理个人业务,所排的队伍越长,则等待的时间越长,银行的服务窗口可类比于服务器。那么如何才能减少排队等候的时间呢,可以多开几个服务窗口,相对应的,我们服务器采用多线程处理,为每一个客户端分配一个子线程进行单独处理,由该线程完成客户端的处理工作。
public class TCPServer { private static int PORT = 1001; public static void main(String[] args) { new TCPServer().startUp(); } public void startUp() { try { // 监听端口 ServerSocket server = new ServerSocket(PORT); while (true) { // 接收连接 Socket client = server.accept(); // 每一个连接代表了一个子线程 new Thread(new ServerThread(client)).start(); } } catch (IOException e) { e.printStackTrace(); } } private class ServerThread implements Runnable { private InputStream is; private OutputStream os; private boolean isRunning = true; public ServerThread(Socket client) { try { is = client.getInputStream(); os = client.getOutputStream(); } catch (IOException e) { isRunning = false; e.printStackTrace(); } } public void run() { while (isRunning) { byte buffer[] = new byte[1024]; int len = -1; try { while ((len = is.read(buffer)) != -1) { System.out.println(new String(buffer, 0, len)); os.write("tcp server".getBytes()); } } catch (IOException e) { isRunning = false; e.printStackTrace(); } } } }}public class TCPServer { private static int PORT = 1001; public static void main(String[] args) { new TCPServer().startUp(); } public void startUp() { try { // 监听端口 ServerSocket server = new ServerSocket(PORT); while (true) { // 接收连接 Socket client = server.accept(); // 每一个连接代表了一个子线程 new Thread(new ServerThread(client)).start(); } } catch (IOException e) { e.printStackTrace(); } } private class ServerThread implements Runnable { private InputStream is; private OutputStream os; private boolean isRunning = true; public ServerThread(Socket client) { try { is = client.getInputStream(); os = client.getOutputStream(); } catch (IOException e) { isRunning = false; e.printStackTrace(); } } public void run() { while (isRunning) { byte buffer[] = new byte[1024]; int len = -1; try { while ((len = is.read(buffer)) != -1) { System.out.println(new String(buffer, 0, len)); os.write("tcp server".getBytes()); } } catch (IOException e) { isRunning = false; e.printStackTrace(); } } } }}
小结
在开发中用到Socket感觉是很高大上的,在Java中有关Socket相关的类都位于java.net包下,sun.*这个包也包含了很多的网络编程相关的类,但是不建议使用这个包下面的API,因为这个包可能会改变,另外这个包不能保证在所有的平台都有包含。
Socket编程重点就在于如何避免多个Socket的读写阻塞,将读和写分别放在不同的子线程中是一种处理方式。在JDK1.4版本中引入了NIO,引入了非阻塞socket,可以不用堵塞进行网络操作。当然了也可以借助于第三方框架如Apache MINA包。
- Java网络编程-初识Socket
- 初识Java TCP/IP Socket-TCP网络编程知识
- 初识Java TCP/IP Socket-UDP网络编程知识
- Java Socket编程(3)初识TCP Socket
- Java Socket编程(3)初识TCP Socket
- python(七)下:初识socket网络编程
- Java网络编程--Socket
- java 网络编程socket
- Java网络编程-Socket
- Java Socket网络编程
- Java Socket网络编程
- Java Socket网络编程
- java网络编程socket
- java网络编程socket
- Java Socket网络编程
- java Socket网络编程
- java Socket网络编程
- java socket网络编程
- linux驱动基础系列--linux spi驱动框架分析
- Scrapy 中的 MongoDB 安装、使用、可视化入门
- LNMP 全功能编译安装 for CentOS6.3笔记
- Windows下交换CapsLock和左ctrl
- Web Service 那点事儿(3)—— SOAP 及其安全控制
- Java网络编程-初识Socket
- Python实现MapReduce
- 支付宝钱包系统架构内部剖析(架构图)
- iOS开发之xib 加载xib视图需要用到的方法
- Activity重新创建之recreate
- BZOJ 3676 UOJ 103 APIO 2014 后缀自动机 Manacher
- FOJ 2214 Knapsack problem 第六届福建省大学生程序设计竞赛 C 01背包DP变种
- SQLite数据库笔记
- dstat默认输出说明