网络编程之TCP通信

时间:2021-06-06 23:59:04

1、TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低

2、Java中基于TCP协议实现网络通信的类

            客户端的Socket类
            服务器端的ServerSocket类
网络编程之TCP通信

 3、Socket通信的步骤

       ① 创建ServerSocket和Socket(服务端和客户端)
       ② 打开连接到Socket的输入/输出流
       ③ 按照协议对Socket进行读/写操作
       ④ 关闭输入输出流、关闭Socket
 
4、服务器端:
        ① 创建ServerSocket对象,绑定监听端口
        ② 通过accept()方法监听客户端请求
        ③ 连接建立后,通过输入流读取客户端发送的请求信息
        ④ 通过输出流向客户端发送回音信息
        ⑤ 关闭相关资源(大型服务器一般不关闭)
网络编程之TCP通信网络编程之TCP通信
 1 package tcp通信;
 2 
 3 import java.io.DataInputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8 
 9 /**
10  * 熟悉流程:
11  * 创建服务器
12  * 模拟登录界面,单向访问
13  * 1、指定端口,使用ServerSocket 创建服务器
14  * 2、阻塞式等待连接accept
15  * 3、输入输出流操作
16  * 4、释放资源
17  * @author liuzeyu12a
18  *
19  */
20 public class LoginServer2 {
21 
22     public static void main(String[] args) throws IOException {
23         System.out.println("---------服务端-----------");
24         String uname = "";
25         String upwd = "";
26         // 1、指定端口 使用ServerSocket创建服务器
27         ServerSocket server = new ServerSocket(8888);
28         
29         //2、阻塞时等待连接,返回一个连接的套接字
30         Socket client = server.accept();
31         System.out.println("一个客户端建立了连接...");
32         
33         //3、输入输出操作,使用操作方便的数据流
34         DataInputStream dis = new DataInputStream(client.getInputStream());
35         String utf = dis.readUTF();
36         String str[] = utf.split("&");
37         for(String info:str) {
38             String[] usrInfo = info.split("=");
39             if(usrInfo[0].equals("uname")) {
40                 uname = usrInfo[1];
41                 System.out.println(usrInfo[0]+":"+usrInfo[1]);
42             }else{
43                 upwd = usrInfo[1];
44                 System.out.println(usrInfo[0]+":"+usrInfo[1]);
45             }
46         }
47         //向客户端返回结果,是否登录成功
48         DataOutputStream dos = new DataOutputStream(client.getOutputStream());
49         if(uname.equals("liuzeyu12a")&&upwd.equals("10086")) {
50             dos.writeUTF("登录成功!!");
51         }else {
52             dos.writeUTF("登录失败!!");
53         }
54         //释放资源
55         server.close();  //大型服务器一般不关闭
56         
57     }
58 }
View Code
 
5、客户端:       
   ① 创建Socket对象,指明需要连接的服务器的地址和端口号
   ② 连接建立后,通过输出流想服务器端发送请求信息
        ③ 通过输入流获取服务器响应的信息
        ④ 关闭响应资源  
网络编程之TCP通信网络编程之TCP通信
 1 package tcp通信;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.DataInputStream;
 5 import java.io.DataOutputStream;
 6 import java.io.IOException;
 7 import java.io.InputStreamReader;
 8 import java.net.Socket;
 9 import java.net.UnknownHostException;
10 
11 /**
12  * 熟悉流程:
13  * 模拟登录界面,单向访问
14  * 1、建立连接,使用Socket创建客户端 + 服务器地址和端口
15  * 2、输入输出操作
16  * 3、释放资源
17  * @author liuzeyu12a
18  *
19  */
20 public class LoginClient2 {
21 
22     public static void main(String[] args) throws UnknownHostException, IOException {
23         System.out.println("---------客户端登录界面-----------");
24         BufferedReader reader = new BufferedReader(
25                 new InputStreamReader(System.in));
26         System.out.print("请输入用户名:");
27         String uname = reader.readLine();
28         System.out.print("请输入用户名:");
29         String upwd = reader.readLine();
30         
31         
32         //1、建立连接,使用Socket创建客户端 + 服务器地址和端口
33         Socket client = new Socket("localhost",8888);
34         
35         //2、输入输出操作
36         DataOutputStream dos = new DataOutputStream(client.getOutputStream());
37         dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
38         
39     
40         //接收服务器返回的结果
41         DataInputStream dis = new DataInputStream(client.getInputStream());
42         String rst = dis.readUTF();
43         System.out.println(rst);
44         //3、释放资源
45         dos.close();
46         client.close();
47     }
48 }
View Code

6、当然,这种客户端请求服务器,然后服务器回应客户端的请求只能实现一对一的服务,在现在的信息化时代,这种通信已经不能满足需求了。

一个服务器应该被多个客户端请求,然后对其一一回应,这才是我们想要的。

这就引出了多线程,在服务器上开启多线程,即一个Socket 多个客户端可以使用。

应用多线程实现服务器与多客户端之间的通信

 

       ① 服务器端创建ServerSocket,循环调用accept()等待客户端连接

 

       ② 客户端创建一个socket并请求和服务器端连接

 

       ③ 服务器端接受客户端请求,创建socket与该客户建立专线连接

 

       ④ 建立连接的两个socket在一个单独的线程上对话

 

       ⑤ 服务器端继续等待新的连接

 

实现代码:

6.1服务端

网络编程之TCP通信网络编程之TCP通信
  1 package tcp通信;
  2 
  3 import java.io.DataInputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.IOException;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 
  9 /**
 10  * 服务端接收多个客户端的请求:
 11  * 在没有使用多线程的情况下要想多个客户机访问服务器,必须等待上一个服务结束
 12  * 后才能进行下一个客户机的连接操作
 13  * 1、使用ServerSocket 建立服务端的套接字绑定本地端口
 14  * 2、阻塞式等待连接Socket accept()
 15  * 3、输入输出流操作
 16  * 4、释放资源
 17  * @author liuzeyu12a
 18  *
 19  */
 20 public class MultiServer {
 21 
 22     public static void main(String[] args) throws Exception {
 23         System.out.println("-------服务器--------");
 24 
 25         boolean isRunning = true;
 26         //1、使用ServerSocket 建立服务端的套接字绑定本地端口
 27         ServerSocket server = new ServerSocket(9999);
 28         
 29         while(isRunning) {
 30             //2、阻塞式等待连接Socket accept()
 31             Socket client = server.accept();
 32             System.out.println("一个客户端建立了连接");
 33             new Thread(new Channel(client)).start();
 34         }
 35         //4、释放资源
 36         server.close();
 37     }
 38     
 39     
 40     //多线程类
 41     //将类改为静态:否则创建对象:new MultiServer().new Channel(client)
 42     //一个Channel代表了一个客户端
 43      static class Channel implements Runnable{
 44          //客户端套接字
 45         private Socket client;
 46         //输入流
 47         private DataInputStream dis;
 48         //输出流
 49         private DataOutputStream dos;
 50         //构造器
 51         public Channel(Socket client) {
 52             this.client = client;
 53             try {
 54                 dis = new DataInputStream(client.getInputStream());
 55                 dos = new DataOutputStream(client.getOutputStream());
 56             } catch (IOException e) {
 57                 e.printStackTrace();
 58                 //如果出异常了
 59                 try {
 60                     client.close();
 61                 } catch (IOException e1) {
 62                     e1.printStackTrace();
 63                     release();
 64                 }
 65             }
 66         }
 67         
 68         //接收客户端信息函数
 69         public String recvive() {
 70             String datas = "";
 71             try {
 72                 datas = dis.readUTF();
 73             } catch (IOException e) {
 74                 e.printStackTrace();
 75             }
 76             return datas;
 77         }
 78         
 79         //发送客户端信息函数
 80         public void send(String msg) {
 81             try {
 82                 dos.writeUTF(msg);
 83                 dos.flush();
 84             } catch (IOException e) {
 85                 e.printStackTrace();
 86             }
 87         }
 88         
 89         public void release() {
 90             try {
 91                 if(null!=client)
 92                 client.close();
 93             } catch (IOException e) {
 94                 e.printStackTrace();
 95             }
 96             try {
 97                 if(null!=dis)
 98                 dis.close();
 99             } catch (IOException e) {
100                 e.printStackTrace();
101             }
102             try {
103                 if(null!=dos)
104                 dos.close();
105             } catch (IOException e) {
106                 e.printStackTrace();
107             }
108         }
109         
110         //线程运行函数
111         @Override
112         public void run() {        
113             //处理客户端发送过来的用户信息
114             String uname = "";
115             String upwd = "";
116             String info[] = recvive().split("&");
117             for(String str: info) {
118                 String[] s = str.split("=");
119                 if(s[0].equals("uname")) {
120                     uname = s[1];
121                 }else if(s[0].equals("upwd")) {
122                     upwd = s[1];
123                 }            
124             }
125             System.out.println("user:"+uname+"\r\n"+"password:"+upwd);
126             
127             //向客户端返回登录信息
128             if(uname.equals("liuzeyu") &&upwd.equals("10086")) {
129                 send("登录成功!!");
130             }else {
131                 send("登录失败!!");
132             }    
133             release();
134         }    
135     }
136 
137 }
View Code

6.2客户端

网络编程之TCP通信网络编程之TCP通信
 1 package tcp通信;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.DataInputStream;
 5 import java.io.DataOutputStream;
 6 import java.io.IOException;
 7 import java.io.InputStreamReader;
 8 import java.net.Socket;
 9 import java.net.UnknownHostException;
10 
11 /**
12  * 熟悉流程:
13  * 模拟登录界面,单向访问
14  * 1、建立连接,使用Socket创建客户端 + 服务器地址和端口
15  * 2、输入输出操作
16  * 3、释放资源
17  * @author liuzeyu12a
18  *
19  */
20 public class LoginClient2 {
21 
22     public static void main(String[] args) throws UnknownHostException, IOException {
23         System.out.println("---------客户端登录界面-----------");
24         BufferedReader reader = new BufferedReader(
25                 new InputStreamReader(System.in));
26         System.out.print("请输入用户名:");
27         String uname = reader.readLine();
28         System.out.print("请输入用户名:");
29         String upwd = reader.readLine();
30         
31         
32         //1、建立连接,使用Socket创建客户端 + 服务器地址和端口
33         Socket client = new Socket("localhost",8888);
34         
35         //2、输入输出操作
36         DataOutputStream dos = new DataOutputStream(client.getOutputStream());
37         dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
38         
39     
40         //接收服务器返回的结果
41         DataInputStream dis = new DataInputStream(client.getInputStream());
42         String rst = dis.readUTF();
43         System.out.println(rst);
44         //3、释放资源
45         dos.close();
46         client.close();
47     }
48 }
View Code

 

7、客户端利用面向对象思想进行封装后

7.1 服务端

网络编程之TCP通信网络编程之TCP通信
  1 package tcp通信;
  2 
  3 import java.io.DataInputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.IOException;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 
  9 /**
 10  * 服务端接收多个客户端的请求:
 11  * 在没有使用多线程的情况下要想多个客户机访问服务器,必须等待上一个服务结束
 12  * 后才能进行下一个客户机的连接操作
 13  * 1、使用ServerSocket 建立服务端的套接字绑定本地端口
 14  * 2、阻塞式等待连接Socket accept()
 15  * 3、输入输出流操作
 16  * 4、释放资源
 17  * @author liuzeyu12a
 18  *
 19  */
 20 public class MultiServer {
 21 
 22     public static void main(String[] args) throws Exception {
 23         System.out.println("-------服务器--------");
 24 
 25         boolean isRunning = true;
 26         //1、使用ServerSocket 建立服务端的套接字绑定本地端口
 27         ServerSocket server = new ServerSocket(9999);
 28         
 29         while(isRunning) {
 30             //2、阻塞式等待连接Socket accept()
 31             Socket client = server.accept();
 32             System.out.println("一个客户端建立了连接");
 33             new Thread(new Channel(client)).start();
 34         }
 35         //4、释放资源
 36         server.close();
 37     }
 38     
 39     
 40     //多线程类
 41     //将类改为静态:否则创建对象:new MultiServer().new Channel(client)
 42     //一个Channel代表了一个客户端
 43      static class Channel implements Runnable{
 44          //客户端套接字
 45         private Socket client;
 46         //输入流
 47         private DataInputStream dis;
 48         //输出流
 49         private DataOutputStream dos;
 50         //构造器
 51         public Channel(Socket client) {
 52             this.client = client;
 53             try {
 54                 dis = new DataInputStream(client.getInputStream());
 55                 dos = new DataOutputStream(client.getOutputStream());
 56             } catch (IOException e) {
 57                 e.printStackTrace();
 58                 //如果出异常了
 59                 try {
 60                     client.close();
 61                 } catch (IOException e1) {
 62                     e1.printStackTrace();
 63                 }
 64             }
 65         }
 66         
 67         //接收客户端信息函数
 68         public String recvive() {
 69             String datas = "";
 70             try {
 71                 datas = dis.readUTF();
 72             } catch (IOException e) {
 73                 e.printStackTrace();
 74             }
 75             return datas;
 76         }
 77         
 78         //发送客户端信息函数
 79         public void send(String msg) {
 80             try {
 81                 dos.writeUTF(msg);
 82                 dos.flush();
 83             } catch (IOException e) {
 84                 e.printStackTrace();
 85             }
 86         }
 87         
 88         public void release() {
 89             try {
 90                 if(null!=client)
 91                 client.close();
 92             } catch (IOException e) {
 93                 e.printStackTrace();
 94             }
 95             try {
 96                 if(null!=dis)
 97                 dis.close();
 98             } catch (IOException e) {
 99                 e.printStackTrace();
100             }
101             try {
102                 if(null!=dos)
103                 dos.close();
104             } catch (IOException e) {
105                 e.printStackTrace();
106             }
107         }
108         
109         //线程运行函数
110         @Override
111         public void run() {        
112             //处理客户端发送过来的用户信息
113             String uname = "";
114             String upwd = "";
115             String info[] = recvive().split("&");
116             for(String str: info) {
117                 String[] s = str.split("=");
118                 if(s[0].equals("uname")) {
119                     uname = s[1];
120                 }else if(s[0].equals("upwd")) {
121                     upwd = s[1];
122                 }            
123             }
124             System.out.println("user:"+uname+"\r\n"+"password:"+upwd);
125             
126             //向客户端返回登录信息
127             if(uname.equals("liuzeyu") &&upwd.equals("10086")) {
128                 send("登录成功!!");
129             }else {
130                 send("登录失败!!");
131             }    
132             release();
133         }    
134     }
135 
136 }
View Code

7.2  客户端

网络编程之TCP通信网络编程之TCP通信
  1 package tcp通信;
  2 
  3 import java.io.BufferedInputStream;
  4 import java.io.BufferedReader;
  5 import java.io.DataInputStream;
  6 import java.io.DataOutputStream;
  7 import java.io.IOException;
  8 import java.io.InputStreamReader;
  9 import java.net.Socket;
 10 import java.net.UnknownHostException;
 11 
 12 /**模拟多个客户端的请求
 13  * 在没有使用多线程的情况下要想多个客户机访问服务器,必须等待上一个服务结束
 14  * 后才能进行下一个客户机的连接操作
 15  * 客户端
 16  * 1、建立连接,使用多Socket建立客户端+绑定服务器的端口和地址
 17  * 2、操作,输入流和输出流的操作
 18  * 3、释放资源
 19  * @author liuzeyu12a
 20  *
 21  */
 22 public class MultiClient {
 23 
 24     public static void main(String[] args) throws UnknownHostException, IOException {
 25         System.out.println("--------客户端---------");
 26         
 27         //1、建立连接,使用多Socket建立客户端+绑定服务器的端口和地址
 28         Socket client = new Socket("localhost",9999);
 29         
 30         //2、操作,输入流和输出流的操作
 31         new Send(client).send();;
 32         
 33         //处理登录信息的反馈
 34         new Receive(client).receive();
 35         
 36         //释放资源
 37         new Send().release();
 38         new Receive().release();
 39     }
 40     
 41     //静态内部类:用于发送
 42     static class Send{
 43         private String msg = "";
 44         private BufferedReader reader; 
 45         
 46         //输出流
 47         private DataOutputStream dos;
 48         //客户端套接字
 49         private Socket client;
 50         //构造器
 51         public Send(Socket client) {
 52             this.client =client;
 53             this.reader= new BufferedReader(
 54                     new InputStreamReader(System.in));
 55             this.msg = init();
 56             try {
 57                 dos = new DataOutputStream(client.getOutputStream());
 58             } catch (IOException e) {
 59                 e.printStackTrace();
 60             }
 61         }
 62         //无参构造器
 63         public Send() {
 64         }
 65         
 66         //发送函数
 67         public void send() {
 68             try {
 69                 dos.writeUTF(msg);
 70             } catch (IOException e) {
 71                 e.printStackTrace();
 72             }
 73             try {
 74                 dos.flush();
 75             } catch (IOException e) {
 76                 e.printStackTrace();
 77             }
 78         }
 79         //释放资源函数
 80         public void release() {
 81             try {
 82                 if(null!=dos)
 83                 dos.close();
 84             } catch (IOException e1) {
 85                 e1.printStackTrace();
 86             }
 87             try {
 88                 if(null!=client)
 89                 client.close();
 90             } catch (IOException e) {
 91                 e.printStackTrace();
 92             }
 93         }
 94         
 95         //初始化信息
 96         public String init() {    
 97             try {
 98                 System.out.print("请输入用户名:");
 99                 String uname = reader.readLine();
100                 System.out.print("请输入密码:");
101                 String upwd = reader.readLine();
102                 return "uname="+uname+"&"+"upwd="+upwd;
103             } catch (IOException e) {
104                 e.printStackTrace();
105             }
106             return "";
107         }
108         
109     }
110 
111 
112     //静态内部类:用于接收
113     static class Receive{
114         //客户端套接字
115         private Socket client;
116         //输入流
117         private DataInputStream dis;
118         //构造器
119         public Receive(Socket client) {
120             this.client =client;
121             try {
122                 dis = new DataInputStream(
123                         new BufferedInputStream(client.getInputStream()));
124             } catch (IOException e) {
125                 e.printStackTrace();
126             }    
127             }
128         
129         //接收函数
130         public void receive() {
131             try {
132                 String rst = dis.readUTF();
133                 System.out.println(rst);
134             } catch (IOException e) {
135                 e.printStackTrace();
136             }
137         }
138         
139         public Receive() {
140         }
141         //释放函数
142         public void release() {
143             try {
144                 if(null!=client)
145                 client.close();
146             } catch (IOException e) {
147                 e.printStackTrace();
148             }
149             try {
150                 if(null!=dis)
151                 dis.close();
152             } catch (IOException e) {
153                 e.printStackTrace();
154             }
155         }
156     
157     }
158 }
View Code
 

附上参考资料

https://www.cnblogs.com/rocomp/p/4790340.html