Java网络编程之Socket

Java网络编程之Socket

一、Socket编程简介

  套接字编程

  利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准。
  通信的两端都要有Socket,是两台机器间通信的端点
  网络通信其实就是Socket间的通信。
  Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
  一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

  基于Socket的TCP编程

  Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示

二、客户端Socket编程

  客户端Socket的工作过程

  ①创建Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。

  ②打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输

  ③按照一定的协议对 Socket  进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。

  ④关闭 Socket:断开客户端到服务器的连接,释放线路

  客户端创建Socket对象

  客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接。Socket的构造方法有:

 

Socket()

          通过系统默认类型的 SocketImpl 创建未连接套接字

 

Socket(InetAddress address, int port)

          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

 

Socket(InetAddress host, int port, boolean stream)

          已过时。 Use DatagramSocket instead for UDP transport.

 

Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

          创建一个套接字并将其连接到指定远程地址上的指定远程端口。

 

Socket(Proxy proxy)

          创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。

protected

Socket(SocketImpl impl)

          使用用户指定的 SocketImpl 创建一个未连接 Socket。

 

Socket(String host, int port)

          创建一个流套接字并将其连接到指定主机上的指定端口号。

 

Socket(String host, int port, boolean stream)

          已过时。 使用 DatagramSocket 取代 UDP 传输。

 

Socket(String host, int port, InetAddress localAddr, int localPort)

          创建一个套接字并将其连接到指定远程主机上的指定远程端口。

   常用的以下两个构造方法

  Socket(String host,int port)throws UnknownHostException,IOException:向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。

  Socket(InetAddress address,int port)throws IOException:根据InetAddress对象所表示的IP地址以及端口号port发起连接。

  客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请求

三、服务器端Socket编程

  服务器程序的工作过程

  ①调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。

  ②调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。

  ③调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。

  ④关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。

  服务器建立ServerSocket对象

  ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的ServerSocket对象。

  所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象

  ServerSocket构造方法

ServerSocket()

          创建非绑定服务器套接字。

ServerSocket(int port)

          创建绑定到特定端口的服务器套接字。

ServerSocket(int port, int backlog)

          利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。

ServerSocket(int port, int backlog, InetAddress bindAddr)

          使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

四、java.net.Socket简介(客户端Socket)

  Socket数据结构

  Socket方法摘要

 void

bind(SocketAddress bindpoint)

          将套接字绑定到本地地址。

 void

close()

          关闭此套接字。

 void

connect(SocketAddress endpoint)

          将此套接字连接到服务器。

 void

connect(SocketAddress endpoint, int timeout)

          将此套接字连接到服务器,并指定一个超时值。

 SocketChannel

getChannel()

          返回与此数据报套接字关联的唯一 SocketChannel 对象(如果有)。

 InetAddress

getInetAddress()

          返回套接字连接的地址。

 InputStream

getInputStream()

          返回此套接字的输入流。

 boolean

getKeepAlive()

          测试是否启用 SO_KEEPALIVE。

 InetAddress

getLocalAddress()

          获取套接字绑定的本地地址。

 int

getLocalPort()

          返回此套接字绑定到的本地端口。

 SocketAddress

getLocalSocketAddress()

          返回此套接字绑定的端点的地址,如果尚未绑定则返回 null

 boolean

getOOBInline()

          测试是否启用 OOBINLINE。

 OutputStream

getOutputStream()

          返回此套接字的输出流。

 int

getPort()

          返回此套接字连接到的远程端口。

 int

getReceiveBufferSize()

          获取此 Socket 的 SO_RCVBUF 选项的值,该值是平台在 Socket 上输入时使用的缓冲区大小。

 SocketAddress

getRemoteSocketAddress()

          返回此套接字连接的端点的地址,如果未连接则返回 null

 boolean

getReuseAddress()

          测试是否启用 SO_REUSEADDR。

 int

getSendBufferSize()

          获取此 Socket 的 SO_SNDBUF 选项的值,该值是平台在 Socket 上输出时使用的缓冲区大小。

 int

getSoLinger()

          返回 SO_LINGER 的设置。

 int

getSoTimeout()

          返回 SO_TIMEOUT 的设置。

 boolean

getTcpNoDelay()

          测试是否启用 TCP_NODELAY。

 int

getTrafficClass()

          为从此 Socket 上发送的包获取 IP 头中的流量类别或服务类型。

 boolean

isBound()

          返回套接字的绑定状态。

 boolean

isClosed()

          返回套接字的关闭状态。

 boolean

isConnected()

          返回套接字的连接状态。

 boolean

isInputShutdown()

          返回是否关闭套接字连接的半读状态 (read-half)。

 boolean

isOutputShutdown()

          返回是否关闭套接字连接的半写状态 (write-half)。

 void

sendUrgentData(int data)

          在套接字上发送一个紧急数据字节。

 void

setKeepAlive(boolean on)

          启用/禁用 SO_KEEPALIVE。

 void

setOOBInline(boolean on)

          启用/禁用 OOBINLINE(TCP 紧急数据的接收者) 默认情况下,此选项是禁用的,即在套接字上接收的 TCP 紧急数据被静默丢弃。

 void

setPerformancePreferences(int connectionTime, int latency, int bandwidth)

          设置此套接字的性能偏好。

 void

setReceiveBufferSize(int size)

          将此 Socket 的 SO_RCVBUF 选项设置为指定的值。

 void

setReuseAddress(boolean on)

          启用/禁用 SO_REUSEADDR 套接字选项。

 void

setSendBufferSize(int size)

          将此 Socket 的 SO_SNDBUF 选项设置为指定的值。

static void

setSocketImplFactory(SocketImplFactory fac)

          为应用程序设置客户端套接字实现工厂。

 void

setSoLinger(boolean on, int linger)

          启用/禁用具有指定逗留时间(以秒为单位)的 SO_LINGER。

 void

setSoTimeout(int timeout)

          启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。

 void

setTcpNoDelay(boolean on)

          启用/禁用 TCP_NODELAY(启用/禁用 Nagle 算法)。

 void

setTrafficClass(int tc)

          为从此 Socket 上发送的包在 IP 头中设置流量类别 (traffic class) 或服务类型八位组 (type-of-service octet)。

 void

shutdownInput()

          此套接字的输入流置于“流的末尾”。

 void

shutdownOutput()

          禁用此套接字的输出流。

 String

toString()

          将此套接字转换为 String

五、java.net.ServerSocket简介(服务端Socket)

  ServerSocket数据结构

  ServerSocket方法摘要

 Socket

accept()

          侦听并接受到此套接字的连接。

 void

bind(SocketAddress endpoint)

          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

 void

bind(SocketAddress endpoint, int backlog)

          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

 void

close()

          关闭此套接字。

 ServerSocketChannel

getChannel()

          返回与此套接字关联的唯一 ServerSocketChannel 对象(如果有)。

 InetAddress

getInetAddress()

          返回此服务器套接字的本地地址。

 int

getLocalPort()

          返回此套接字在其上侦听的端口。

 SocketAddress

getLocalSocketAddress()

          返回此套接字绑定的端点的地址,如果尚未绑定则返回 null

 int

getReceiveBufferSize()

          获取此 ServerSocket 的 SO_RCVBUF 选项的值,该值是将用于从此 ServerSocket 接受的套接字的建议缓冲区大小。

 boolean

getReuseAddress()

          测试是否启用 SO_REUSEADDR。

 int

getSoTimeout()

          获取 SO_TIMEOUT 的设置。

protected  void

implAccept(Socket s)

          ServerSocket 的子类使用此方法重写 accept() 以返回它们自己的套接字子类。

 boolean

isBound()

          返回 ServerSocket 的绑定状态。

 boolean

isClosed()

          返回 ServerSocket 的关闭状态。

 void

setPerformancePreferences(int connectionTime, int latency, int bandwidth)

          设置此 ServerSocket 的性能首选项。

 void

setReceiveBufferSize(int size)

          为从此 ServerSocket 接受的套接字的 SO_RCVBUF 选项设置默认建议值。

 void

setReuseAddress(boolean on)

          启用/禁用 SO_REUSEADDR 套接字选项。

static void

setSocketFactory(SocketImplFactory fac)

          为应用程序设置服务器套接字实现工厂。

 void

setSoTimeout(int timeout)

          通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。

 String

toString()

          作为 String 返回此套接字的实现地址和实现端口。

六、示例分析

  从客户端发送文件给服务端,服务端保存到本地,并返回发送成功给客户端

  1 package me.net.socket;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileNotFoundException;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 import java.io.InputStream;
  9 import java.io.OutputStream;
 10 import java.net.InetAddress;
 11 import java.net.ServerSocket;
 12 import java.net.Socket;
 13 import java.net.UnknownHostException;
 14 
 15 import org.junit.Test;
 16 
 17 /**
 18  * 从客户端发送文件给服务端,服务端保存到本地,并返回发送成功给客户端
 19  * 
 20  * @author Administrator
 21  *
 22  */
 23 public class TestTCP3 {
 24 
 25     /**
 26      * 模拟客户端
 27      */
 28     @Test
 29     public void client() {
 30     Socket socket = null;
 31     FileInputStream fis = null;
 32     InputStream is = null;
 33     OutputStream os = null;
 34     try {
 35         // 1.创建socket对象
 36         socket = new Socket(InetAddress.getByName("127.0.0.1"), 8989);
 37         // 2.向服务端发送数据
 38         os = socket.getOutputStream();
 39         fis = new FileInputStream(new File("1.jpg"));
 40         byte[] b = new byte[20];
 41         int len = 0;
 42         while ((len = fis.read(b)) != -1) {
 43         os.write(b, 0, len);
 44         }
 45         os.flush();
 46         socket.shutdownOutput();
 47         // 3.接受来自服务端的响应
 48         is = socket.getInputStream();
 49         byte[] b1 = new byte[200];
 50         int len1 = 0;
 51         while ((len1 = is.read(b1, 0, b1.length)) != -1) {
 52         System.out.print(new String(b1, 0, len1, "UTF-8"));
 53         }
 54         socket.shutdownInput();
 55     } catch (UnknownHostException e) {
 56         e.printStackTrace();
 57     } catch (FileNotFoundException e) {
 58         e.printStackTrace();
 59     } catch (IOException e) {
 60         e.printStackTrace();
 61     } finally {
 62         // 4.关闭io流
 63         if (is != null) {
 64         try {
 65             is.close();
 66         } catch (IOException e) {
 67             e.printStackTrace();
 68         }
 69         }
 70         if (fis != null) {
 71         try {
 72             fis.close();
 73         } catch (IOException e) {
 74             e.printStackTrace();
 75         }
 76         }
 77         if (os != null) {
 78         try {
 79             os.close();
 80         } catch (IOException e) {
 81             e.printStackTrace();
 82         }
 83         }
 84         if (socket != null) {
 85         try {
 86             socket.close();
 87         } catch (IOException e) {
 88             e.printStackTrace();
 89         }
 90         }
 91     }
 92     }
 93 
 94     /**
 95      * 模拟服务器端
 96      */
 97     @Test
 98     public void server() {
 99     ServerSocket ss = null;
100     Socket socket = null;
101     InputStream is = null;
102     FileOutputStream fos = null;
103     OutputStream os = null;
104     try {
105         // 1.创建服务器端socket对象
106         ss = new ServerSocket(8989);
107         socket = ss.accept();
108         // 2.收取来自客户端的数据
109         is = socket.getInputStream();
110         fos = new FileOutputStream(new File("2.jpg"));
111         byte[] b = new byte[20];
112         int len = 0;
113         while ((len = is.read(b)) != -1) {
114         fos.write(b, 0, len);
115         }
116         fos.flush();
117         System.out.println("收到来自于" + socket.getInetAddress().getHostName() + "的文件!");
118         socket.shutdownInput();
119         // 3.向客户端发出回应
120         os = socket.getOutputStream();
121         os.write("已收到客户端发来的图片".getBytes("UTF-8"));
122         os.flush();
123         socket.shutdownOutput();
124     } catch (FileNotFoundException e) {
125         e.printStackTrace();
126     } catch (IOException e) {
127         e.printStackTrace();
128     } finally {
129         // 4.关闭io流
130         if (os != null) {
131         try {
132             os.close();
133         } catch (IOException e) {
134             e.printStackTrace();
135         }
136         }
137         if (fos != null) {
138         try {
139             fos.close();
140         } catch (IOException e) {
141             e.printStackTrace();
142         }
143         }
144         if (is != null) {
145         try {
146             is.close();
147         } catch (IOException e) {
148             e.printStackTrace();
149         }
150         }
151         if (socket != null) {
152         try {
153             socket.close();
154         } catch (IOException e) {
155             e.printStackTrace();
156         }
157         }
158         if (ss != null) {
159         try {
160             ss.close();
161         } catch (IOException e) {
162             e.printStackTrace();
163         }
164         }
165     }
166     }
167 }
View Code

如果,您对我的这篇博文有什么疑问,欢迎评论区留言,大家互相讨论学习。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博文感兴趣,可以关注我的后续博客,我是【AlbertRui】。

转载请注明出处和链接地址,欢迎转载,谢谢!

原文地址:https://www.cnblogs.com/albertrui/p/8399079.html