19.2 基于tcp协议的编程模型(重点)

19.2.1 C/S架构的简介

在C/S模式下客户向服务器发出服务请求,服务器接收请求后提供服务。
例如:在一个酒店中,顾客找服务员点菜,服务员把点菜单通知厨师,厨师按点菜单做好菜后让服
务员端给客户,这就是一种C/S工作方式。如果把酒店看作一个系统,服务员就是客户端,厨师就
是服务器。这种系统分工和协同工作的方式就是C/S的工作方式。
客户端部分:为每个用户所专有的,负责执行前台功能。
服务器部分:由多个用户共享的信息与功能,招待后台服务。

19.2.2 编程模型

服务器:

(1)创建ServerSocket类型的对象并提供端口号;
(2)等待客户端的连接请求,调用accept()方法;
(3)使用输入输出流进行通信;
(4)关闭Socket;

客户端:

(1)创建Socket类型的对象并提供服务器的IP地址和端口号;
(2)使用输入输出流进行通信;
(3)关闭Socket;

19.2.3 相关类和方法的解析

(1)ServerSocket类

java.net.ServerSocket类主要用于描述服务器套接字信息(大插排)。
常用的方法如下:
方法声明 功能介绍
**ServerSocket(int port) **
**根据参数指定的端口号来构造对象**
**Socket accept() **
**侦听并接收到此套接字的连接请求**
**void close() **
**用于关闭套接字**

(2)Socket类

java.net.Socket类主要用于描述客户端套接字,是两台机器间通信的端点(小插排)。
常用的方法如下:
方法声明 功能介绍
Socket(String host, int port)
根据指定主机名和端口来构造对象
InputStream getInputStream()
用于获取当前套接字的输入流
OutputStream getOutputStream()
用于获取当前套接字的输出流
void close()
用于关闭套接字

(3)注意事项

客户端 Socket 与服务器端 Socket 对应, 都包含输入和输出流。
客户端的socket.getInputStream() 连接于服务器socket.getOutputStream()。
客户端的socket.getOutputStream()连接于服务器socket.getInputStream()

案例代码

客户端向服务其发送数据的实现

客户端类

**package **``**task19**``**;**``**import **``**java.io.IOException**``**;**``**import **``**java.io.PrintStream**``**;**``**import **``**java.net.Socket**``**;**``**public class **``**ClientString {**
** **``**public static void **``**main**``**(String[] args) {**
** Socket s= **``**null;**``** **``**PrintStream ps = **``**null;**``** try **``**{**
** **``**//1.**``**创建**``**Socket**``**类型的对象并提供服务器的主机名和端口号**``** **``**s = **``**new **``**Socket(**``**"127.0.0.1"**``**,**``**8888**``**)**``**;**``** **``**System.**``**_out_**``**.println(**``**"**``**连接服务器成功**``**"**``**)**``**;**``** **``**//2.**``**实现输入输出流进行通信**``** **``**//**``**实现客户端向服务器发送内容**``** **``**Thread.**``**_sleep_**``**(**``**10000**``**)**``**;**``** **``**ps = **``**new **``**PrintStream(s.getOutputStream())**``**;**``** **``**ps.println(**``**"hello"**``**)**``**;**``** **``**System.**``**_out_**``**.println(**``**"**``**客户端发送成功**``**"**``**)**``**;**``** **``**} **``**catch **``**(IOException | InterruptedException e) {**
** e.printStackTrace()**``**;**``** **``**} **``**finally **``**{**
** **``**if **``**( **``**null **``**!=ps ) {**
** ps.close()**``**;**``** **``**}**
** **``**if **``**(**``**null **``**!= s){**
** **``**try **``**{**
** s.close()**``**;**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **``**}**
** }**
** }**
** }**
**}**

服务器端类

**package **``**task19**``**;**``**import **``**java.io.BufferedReader**``**;**``**import **``**java.io.IOException**``**;**``**import **``**java.io.InputStreamReader**``**;**``**import **``**java.net.ServerSocket**``**;**``**import **``**java.net.Socket**``**;**``**public class **``**ServerStringTest {**
** **``**public static void **``**main**``**(String[] args) {**
** ServerSocket ss = **``**null;**``** **``**Socket s = **``**null;**``** **``**BufferedReader br = **``**null;**``** try **``**{**
** **``**//1.**``**创建**``**serverSocket**``**类型的对象并提供端口号**``** **``**ss = **``**new **``**ServerSocket(**``**8888**``**)**``**;**``** **``**System.**``**_out_**``**.println(**``**"**``**等待客户端连接请求**``**····"**``**)**``**;**``** **``**//**``**当没有客户端连接时,则服务其阻塞在**``**accept()**``**方法的调用这里**``** **``**s = ss.accept()**``**;**``** **``**System.**``**_out_**``**.println(**``**"**``**客户端连接成功**``**"**``**)**``**;**``** **``**br = **``**new **``**BufferedReader(**``**new **``**InputStreamReader(s.getInputStream()))**``**;**``** **``**String s1 = br.readLine()**``**;**``** **``**System.**``**_out_**``**.println(**``**"**``**客户端发来的内容是**``**"**``**+s1)**``**;**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **``**} **``**finally **``**{**
** **``**//**``**关闭**``**Socket**``**并释放有关资源**``** **``**if **``**(**``**null **``**!= br){**
** **``**try **``**{**
** br.close()**``**;**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **``**}**
** }**
** **``**if **``**(**``**null**``**!= s) {**
** **``**try **``**{**
** s.close()**``**;**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **``**}**
** }**
** **``**if **``**(**``**null **``**!= ss) {**
** **``**try **``**{**
** ss.close()**``**;**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **``**}**
** }**
** }**
** }**
**}**

服务器向客户端回发数据的实现

// 服务器类

**package **``**task19**``**;**
**import **``**java.io.BufferedReader**``**;**
**import **``**java.io.IOException**``**;**
**import **``**java.io.InputStreamReader**``**;**
**import **``**java.io.PrintStream**``**;**
**import **``**java.net.ServerSocket**``**;**
**import **``**java.net.Socket**``**;**
**public class **``**Server1Test {**
** **``**public static void **``**main**``**(String[] args) {**
** ServerSocket ss = **``**null;**``** **
** ** **Socket s = **``**null;**``** **
** ** **BufferedReader br = **``**null;**``** **
** ** **PrintStream ps = **``**null;**``** **
** try **``**{**
** **``**//1.**``**创建一个**``**ServerSocket**``**类型的对象并提供端口号**``** **
** **``**ss = **``**new **``**ServerSocket(**``**8888**``**)**``**;**``** **
**System.**``**_out_**``**.println(**``**"**``**等待客户端连接请求**``**·····"**``**)**``**;**``** **
** **``**//2.**``**等待客户端连接时,调用**``**accept**``**方法**``** **
** **``**s = ss.accept()**``**;**``** **
** **``**System.**``**_out_**``**.println(**``**"**``**客户端连接成功**``**"**``**)**``**;**``** **
** **``**//3.**``**使用输入输出进行通信**``** **
** **``**// **``**接受客户端发送的消息**
** **``**br = **``**new **``**BufferedReader(**``**new **``**InputStreamReader(s.getInputStream()))**``**;**``** **``**String s1 = br.readLine()**``**;**``** **
** **``**System.**``**_out_**``**.println(**``**"**``**客户端发来的内容是**``**"**``**+s1)**``**;**
** **``**// **``**实现服务器向客户端回发字符串换内容**``** **
** **``**// **``**服务器向客户端发送消息**``** **
** **``**ps = **``**new **``**PrintStream(s.getOutputStream())**``**;**``** **
** **``**ps.println(**``**"**``**我 收到了**``**"**``**)**``**;**
** **``**System.**``**_out_**``**.println(**``**"**``**服务器发送成功**``**"**``**)**``**;**``** **
** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;**``** **
** **``**} **``**finally **``**{**
** **``**//**``**关闭服务器释放有关资源**``** **
** **``**if**``**(**``**null **``**!= ps){**
** ps.close()**``**;**``** **``**}**
<br />`** **if **(**null **!= br) {**`<br />`** **try **{**`<br />`** br.close()**;** **} **catch **(IOException e) {<br /> e.printStackTrace()**;** **}**`<br />`** }**`<br />`** **if**(**null**!= ss) {**`<br />`** **try **{**`<br />`** ss.close()**;** **} **catch **(IOException e) {<br /> e.printStackTrace()**;** **}**`<br />`** }**`<br />`** **if**(**null **!= s){**`<br />`** **try **{**`<br />`** s.close()**;** **} **catch **(IOException e) {<br /> e.printStackTrace()**;** `**}**
** }**
** }**

客户端类

package**task19**;
import**java.io.*;<br />importjava.net.Socket;<br />importjava.util.Scanner**;
public class**Client1Test {
`****public static void ****main****(String[] args) {**<br />** Socket sk = ****null;
**** ****PrintStream ps =****null;**** **<br />** ** **BufferedReader br = ****null;**** **<br />** ****Scanner sc = ****null;
**** try ****{**<br />** sk = ****new ****Socket(****“127.0.0.1”****,****8888****)****;
**** ****System.****out****.println(********服务器连接成功********)****;
**** ****//2.****输入输出流进行通信
**** ****// Thread.sleep(10000);
**** //****实现客户端发送的内容由用户输入
**** ****//****客户端向服务器发送消息
**** ****System.****out****.println(********请输入要发送到的内容********)****;
**** ****sc= ****new ****Scanner(System.****in****)****;
**** ****String str1 = sc.next()****;
**** ****//.****客户端向服务器发送字符串
**** ****ps = ****new ****PrintStream(sk.getOutputStream())****;
**** ****ps.println(str1)****;**** **** **<br />**


**//客户端接收服务器回复的消息<br />`****br= ****new ****BufferedReader(****new ****InputStreamReader(sk.getInputStream()))****;
**** ****String str2= br.readLine()****;
**** ****System.****out****.println(********服务器回复的内容是:********+str2)****;**<br />** ****} ****catch ****(IOException ****/| InterruptedException/ ****e) {**<br />** e.printStackTrace()****;
**** ****} ****finally ****{**<br />** ****//3.****关羽****Cocket ****并释放有关资源
**** ****if****(****null ****!= br){**<br />** ****try ****{**<br />** br.close()****;
**** ****} ****catch ****(IOException e) {**<br />** e.printStackTrace()****;
**** ****}**<br />** }`**

**if(null**!= ps){
ps.close()**;<br /> }
`****if****(****null****!= sc){**<br />** sc.close()****;
**** ****}`**

**if(null**!= sk) {
**try**{
sk.close()**;<br /> }catch(IOException e) {
e.printStackTrace();<br />`****}**<br />** }**<br />** }`**

}
}

服务器和客户端连续通信的实现

服务器类

**package **``**task19**``**;<br />**``**import **``**java.io.BufferedReader**``**;<br />**``**import **``**java.io.IOException**``**;<br />**``**import **``**java.io.InputStreamReader**``**;<br />**``**import **``**java.io.PrintStream**``**;<br />**``**import **``**java.net.ServerSocket**``**;<br />**``**import **``**java.net.Socket**``**;<br />**``**public class **``**Server1Test {**
** **``**public static void **``**main**``**(String[] args) {**
** ServerSocket ss = **``**null;<br />**``** **``**Socket s = **``**null;<br />**``** **``**BufferedReader br = **``**null;<br />**``** **``**PrintStream ps = **``**null;<br />**``** try **``**{**
** **``**//1.**``**创建一个**``**ServerSocket**``**类型的对象并提供端口号<br />**``** **``**ss = **``**new **``**ServerSocket(**``**8888**``**)**``**;<br />**``** **``**System.**``**_out_**``**.println(**``**"**``**等待客户端连接请求**``**·····"**``**)**``**;<br />**``** **``**//2.**``**等待客户端连接时,调用**``**accept**``**方法<br />**``** **``**s = ss.accept()**``**;<br />**``** **``**System.**``**_out_**``**.println(**``**"**``**客户端连接成功**``**"**``**)**``**;<br />**``** **``**br = **``**new **``**BufferedReader(**``**new **``**InputStreamReader(s.getInputStream()))**``**;<br />**``** **``**ps = **``**new **``**PrintStream(s.getOutputStream())**``**;<br />**``** **``**//3.**``**使用输入输出进行通信<br />**``** **``**// **``**接受客户端发送的消息<br />**``** **``**while **``**(**``**true**``**) {**
** String s1 = br.readLine()**``**;<br />**``** **``**System.**``**_out_**``**.println(**``**"**``**客户端发来的内容是**``**" **``**+ s1)**``**;<br />**``** **``**//**``**当客户端发来**``**bye **``**,则聊天结束<br />**``** **``**if**``**(**``**"bye"**``**.equals(s1)){**
** System.**``**_out_**``**.println(**``**"**``**客户端已经下线**``**"**``**)**``**;<br />**``** break;<br />**``** **``**}**
<br />`** **// **实现服务器向客户端回发字符串换内容<br />** **// **服务器向客户端发送消息
** **ps.println(**"**我 收到了**"**)**;<br />** **System.**out**.println(****服务器发送成功****)**;
** **}<br /> } **catch **(IOException e) {<br /> e.printStackTrace()**;<br />** **} **finally **{**`<br />`** **//**关闭服务器释放有关资源<br />** **if**(**null **!= ps){<br /> ps.close()**;<br />** **}**`<br />
** **``**if **``**(**``**null **``**!= br) {**
** **``**try **``**{**
** br.close()**``**;<br />**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;<br />**``** **``**}**
** }**
** **``**if**``**(**``**null**``**!= ss) {**
** **``**try **``**{**
** ss.close()**``**;<br />**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;<br />**``** **``**}**
** }**
** **``**if**``**(**``**null **``**!= s){**
** **``**try **``**{**
** s.close()**``**;<br />**``** **``**} **``**catch **``**(IOException e) {**
** e.printStackTrace()**``**;<br />**``** **``**}**
** }**
** }**
`<br /> }<br />}`

客户端类

**package **``**task19**``**;<br />**``**import **``**java.io.***``**;<br />**``**import **``**java.net.Socket**``**;<br />**``**import **``**java.util.Scanner**``**;<br />**``**public class **``**Client1Test {**
** **``**public static void **``**main**``**(String[] args) {**
<br />`** Socket sk = **null;
** **PrintStream ps =**null;<br />** **BufferedReader br = **null;
** **Scanner sc = **null;<br />** try **{**`<br />
** sk = **``**new **``**Socket(**``**"127.0.0.1"**``**,**``**8888**``**)**``**;<br />**``** **``**System.**``**_out_**``**.println(**``**"**``**服务器连接成功**``**"**``**)**``**;<br />**``** **``**sc = **``**new **``**Scanner(System.**``**_in_**``**)**``**;<br />**``** **``**ps = **``**new **``**PrintStream(sk.getOutputStream())**``**;<br />**``** **``**br = **``**new **``**BufferedReader(**``**new **``**InputStreamReader(sk.getInputStream()))**``**;<br />**``** **``**//2.**``**输入输出流进行通信<br />**``** **``**while **``**(**``**true**``**) {**
** **``**// Thread.sleep(10000);<br />**``** //**``**实现客户端发送的内容由用户输入<br />**``** **``**//**``**客户端向服务器发送消息<br />**``** **``**System.**``**_out_**``**.println(**``**"**``**请输入要发送到的内容**``**"**``**)**``**;<br />**``** **``**String str1 = sc.next()**``**;<br />**``** **``**//.**``**客户端向服务器发送字符串<br />**``** **``**ps.println(str1)**``**;<br />**``** **``**//**``**当发送的内容是**``**bye **``**则聊天结束<br />**``** **``**if **``**(**``**"bye"**``**.equals(str1)){**
** System.**``**_out_**``**.println(**``**"**``**聊天结束**``**"**``**)**``**;<br />**``** break;<br />**``** **``**}**
<br />`** **//**客户端接收服务器回复的消息<br />** **String str2 = br.readLine()**;
** **System.**_out_**.println(**"**服务器回复的内容是:**" **+ str2)**;<br />** **}**`<br />`** } **catch **(IOException **/| InterruptedException/ **e) {**`<br />`** e.printStackTrace()**;
** **} **finally **{<br /> **//3.**关羽**Cocket **并释放有关资源
** **if**(**null **!= br){**`<br />`** **try **{**`<br />`** br.close()**;
** **} **catch **(IOException e) {<br /> e.printStackTrace()**;<br />** **}**`<br />`** }**`<br />
** **``**if **``**(**``**null **``**!= ps){**
** ps.close()**``**;<br />**``** **``**}**
** **``**if**``**(**``**null**``**!= sc){**
** sc.close()**``**;<br />**``** **``**}**
<br />`** **if **(**null **!= sk) {**`<br />`** **try **{**`<br />`** sk.close()**;
** **} **catch **(IOException e) {<br /> e.printStackTrace()**;<br />** **}**`<br />`** }**`<br />
** }**
** **
** }**
**}**

服务器采用多线程机制的实现

服务器类

**package com.lagou.task19;**
**import java.io.BufferedReader;**
**import java.io.IOException;**
**import java.io.InputStreamReader;**
**import java.io.PrintStream;**
**import java.net.ServerSocket;**
**import java.net.Socket;**
**public class ServerStringTest {**
** public static void main(String[] args) {**
** ServerSocket ss = null;**
** Socket s = null;**
** try {**
** // 1.创建ServerSocket类型的对象并提供端口号**
** ss = new ServerSocket(8888);**
** // 2.等待客户端的连接请求,调用accept方法**
** while(true) {**
** System.out.println("等待客户端的连接请求...");**
** // 当没有客户端连接时,则服务器阻塞在accept方法的调用这里**
** s = ss.accept();**
** System.out.println("客户端" + s.getInetAddress() + "连接成功!");**
** // 每当有一个客户端连接成功,则需要启动一个新的线程为之服务**
** new ServerThread(s).start();**
** }**
** } catch (IOException e) {**
** e.printStackTrace();**
** } finally {**
** // 4.关闭Socket并释放有关的资源**
** if (null != ss) {**
** try {**
** ss.close();**
** } catch (IOException e) {**
** e.printStackTrace();**
** }**
** }**
** }**
** }**
**}**

客户端类

**package com.lagou.task19;**
**import com.lagou.task10.StaticOuter;**
**import java.io.BufferedReader;**
**import java.io.IOException;**
**import java.io.InputStreamReader;**
**import java.io.PrintStream;**
**import java.net.Socket;**
**import java.util.Scanner;**
**public class ClientStringTest {**
** public static void main(String[] args) {**
** Socket s = null;**
** PrintStream ps = null;**
** Scanner sc = null;**
** BufferedReader br = null;**
** try {**
** // 1.创建Socket类型的对象并提供服务器的主机名和端口号**
** s = new Socket("127.0.0.1", 8888);**
** System.out.println("连接服务器成功!");**
** // 2.使用输入输出流进行通信**
** sc = new Scanner(System.in);**
** ps = new PrintStream(s.getOutputStream());**
** br = new BufferedReader(new InputStreamReader(s.getInputStream()));**
** while(true) {**
** //Thread.sleep(10000);**
** // 实现客户端发送的内容由用户从键盘输入**
** System.out.println("请输入要发送的数据内容:");**
** String str1 = sc.next();**
** // 实现客户端向服务器发送字符串内容"hello"**
** //ps.println("hello");**
** ps.println(str1);**
** System.out.println("客户端发送数据内容成功!");**
** // 当发送的数据内容为"bye"时,则聊天结束**
** if ("bye".equalsIgnoreCase(str1)) {**
** System.out.println("聊天结束!");**
** break;**
** }**
** // 实现接收服务器发来的字符串内容并打印**
** String str2 = br.readLine();**
** System.out.println("服务器回发的消息是:" + str2);**
** }**
** } catch (IOException /*| InterruptedException*/ e) {**
** e.printStackTrace();**
** } finally {**
** // 3.关闭Socket并释放有关的资源**
** if (null != br) {**
** try {**
** br.close();**
** } catch (IOException e) {**
** e.printStackTrace();**
** }**
** }**
** if (null != ps) {**
** ps.close();**
** }**
** if (null != sc) {**
** sc.close();**
** }**
** if (null != s) {**
** try {**
** s.close();**
** } catch (IOException e) {**
** e.printStackTrace();**
** }**
** }**
** }**
** }**
**}**

线程类

**package com.lagou.task19;**
**import java.io.BufferedReader;**
**import java.io.IOException;**
**import java.io.InputStreamReader;**
**import java.io.PrintStream;**
**import java.net.InetAddress;**
**import java.net.Socket;**
**public class ServerThread extends Thread {**
** private Socket s;**
** public ServerThread(Socket s) {**
** this.s = s;**
** }**
** @Override**
** public void run() {**
** BufferedReader br = null;**
** PrintStream ps = null;**
** try {**
** // 3.使用输入输出流进行通信**
** br = new BufferedReader(new InputStreamReader(s.getInputStream()));**
** ps = new PrintStream(s.getOutputStream());**
** while(true) {**
** // 实现对客户端发来字符串内容的接收并打印**
** // 当没有数据发来时,下面的方法会形成阻塞**
** String s1 = br.readLine();**
** InetAddress inetAddress = s.getInetAddress();**
** System.out.println("客户端" + inetAddress + "发来的字符串内容是:" + s1);**
** // 当客户端发来的内容为"bye"时,则聊天结束**
** if ("bye".equalsIgnoreCase(s1)) {**
** System.out.println("客户端" + inetAddress + "已下线!");**
** break;**
** }**
** // 实现服务器向客户端回发字符串内容"I received!"**
** ps.println("I received!");**
** System.out.println("服务器发送数据成功!");**
** }**
** } catch (IOException e) {**
** e.printStackTrace();**
** } finally {**
** if (null != ps) {**
** ps.close();**
** }**
** if (null != br) {**
** try {**
** br.close();**
** } catch (IOException e) {**
** e.printStackTrace();**
** }**
** }**
** if (null != s) {**
** try {**
** s.close();**
** } catch (IOException e) {**
** e.printStackTrace();**
** }**
** }**
** }**
** }**
**}**