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 />
import
java.net.Socket
;<br />
import
java.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();**
** }**
** }**
** }**
** }**
**}**