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();**** }**** }**** }**** }****}**
