1 什么是Socket编程?

  • 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称之为一个Socket。Socket的英文原意是“孔”或者是“插座”。通常也称之为“套接字”,用于描述IP地址和端口,可以用来实现不同计算机之间的通信。每种服务都打开一个Socket,并绑定到一个端口中,不同的端口对应着不同的服务。Socket正如其英文原意那样,像一个多孔插座,一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。客户软件将插头插到不同编号的插座,就可以得到不同的服务。

2 连接过程

  • 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
  • 第一步:服务器监听,是服务器套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
  • 第二步:客户端请求,是指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
  • 第三步:连接确认,是指当服务器端套接字监听到或者接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

3 Java中如何实现Socket编程

  • JavaSE中提供了实现Socket编程的API,让网络编程变得更简单,更夹面向对象。实现两台计算机(两个服务)之间的通讯,至少要编写以下的代码: a、服务器端Server.java: i、创建服务器端套接字,表示创建一个服务,并绑定端口号8080。 ii、开始监听网络,准备接收客户端消息,程序在此等待,客户端发送请求之后,接收客户端套接字。 iii、接收客户端消息:
  • java.net.Socket类中getInputStream()方法返回这个Socket类对象的字节输入流: v、读取客户端消息: vi、关闭流,关闭客户端套接字和关闭服务器端套接字:
  • 自定义Server类的示例代码:
		package com.geeklicreed.socket;
		import java.io.BufferedReader;
		import java.io.IOException;
		import java.io.InputStreamReader;
		import java.net.ServerSocket;
		import java.net.Socket;
		public class Server {
				public static void main(String[] args) {
						ServerSocket serverSocket = null;
						Socket clientSocket = null;
						BufferedReader br = null;
						try {
								//1、创建服务器端套接字对象,表示创建一个服务,并且将该服务绑定到8080端口上
								serverSocket = new ServerSocket(8080);
								//2、开始监听网络,准备接收客户端的请求,程序在这等待,当客户端发起请求后,接收客户端套接字
								clientSocket = serverSocket.accept();
								System.out.println("clientSocket:" + clientSocket);
								//3、接收client消息
								br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
								//4、读取client消息
								String temp = null;
								while((temp = br.readLine()) != null){
										System.out.println(temp);
								}
						} catch (Exception e) {
								e.printStackTrace();
						} finally {
								//关闭流
								if(br != null){
										try {
												br.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
								//关闭客户端套接字
								if(clientSocket != null){
										try {
												clientSocket.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
								//关闭服务端套接字
								if(serverSocket != null){
										try {
												serverSocket.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
						}
				}
		}

b、客户端Client.java: i、创建客户端套接字,指向某台电脑的某台服务 ii、发送消息 iii、发送

  • java.net.Socket类中getOutputStream()方法返回这个Socket类对象的字节输出流:

  • java.io.PrintWriter打印字符输出流类中的print(String s)方法:流中输出一个字符串 v、关闭流,关闭客户端套接字

  • 自定义Client类的示例代码:

		import java.io.IOException;
		import java.io.PrintWriter;
		import java.net.Socket;

		public class Client {
				public static void main(String[] args) {
						Socket clientSocket = null;
						PrintWriter out = null;
						try {
								//1、创建客户端套接字,指向某台计算机上的某台服务
								clientSocket = new Socket("192.168.0.160",8080);
								//2、发送消息
								String msg = "Hello World!";
								out = new PrintWriter(clientSocket.getOutputStream());
								//3、发送
								out.print(msg);
								out.flush();
						} catch (Exception e) {
								e.printStackTrace();
						} finally {
								//关闭流
								if(out != null){
										out.close();
								}
								//关闭客户端套接字
								if(clientSocket != null){
										try {
												clientSocket.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}    
						}
				}
		}

4 读取的从浏览器发送的HTTP请求协议

上面的客户端程序不再使用 java 代码,我们尝试将“客户端程序”改为“浏览器客户端软件”,编写以下服务器端程序 。

		package com.geeklicreed.socket;

		import java.io.BufferedReader;
		import java.io.IOException;
		import java.io.InputStreamReader;
		import java.net.ServerSocket;
		import java.net.Socket;
		//服务器,接收浏览器client发送的请求
		public class Server {

				public static void main(String[] args) {
						ServerSocket serverSocket = null;
						Socket clientSocket = null;
						BufferedReader br = null;
						try {
								//1、创建服务器端套接字对象,表示创建一个服务,并且将该服务绑定到8080端口上
								serverSocket = new ServerSocket(8080);
								//2、开始监听网络,准备接收客户端的请求,程序在这等待,当客户端发起请求后,接收客户端套接字
								clientSocket = serverSocket.accept();
								System.out.println("clientSocket:" + clientSocket); //打印客户端套接字
								//3、接收client消息
								br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
								//4、读取client消息
								String msgFromClient = null;
								while((msgFromClient = br.readLine()) != null){
										System.out.println(msgFromClient);
								}
						} catch (Exception e) {
								e.printStackTrace();
						} finally {
								//关闭流
								if(br != null){
										try {
												br.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
								//关闭客户端套接字
								if(clientSocket != null){
										try {
												clientSocket.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
								//关闭服务端套接字
								if(serverSocket != null){
										try {
												serverSocket.close();
										} catch (IOException e) {
												e.printStackTrace();
										}
								}
						}
				}

		}
	```
-  读取从浏览器中发送的HTTP请求协议:打开 FF  浏览器(标准浏览器),在地址栏上输入以下 URL ,然后敲回,控制台中显示如下内容:
![](http://i2.51cto.com/images/blog/201711/30/a2104cb30630bc7b5ed3c3e88363a602.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
![](http://i2.51cto.com/images/blog/201711/30/fd17f77be2634296f4f0a364fed07488.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)