基于TCP/IP的socket网络通信

1.系统设计

1.1服务器端

第一步:用指定的端口号和服务器的IP建立一个ServerSocket对象。
第二步:建立一个Socket对象来接收链接。
第三步:定义DataInputStream读取客户端传来的信息,定义DataOutputStream向客户端发送信息。
第四步:读取客户端的消息;回复客户端消息。

1.2客户端

第一步:用指定的端口号和服务器的IP建立一个socket对象。
第二步:建立一个Socket对象来接收链接。
第三步:定义DataInputStream读取服务器传来的信息,定义DataOutputStream向服务器发送信息。
第四步:读取服务器的消息,回复服务器的消息。

2.程序设计

2.1服务器端

2.1.1StringServer类

mport java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class StringServer {
    // 提供服务
    public void service() {
        int i = 1;
        try {
            // 建立服务器连接,设定客户连接请求队列的长度
            ServerSocket server = new ServerSocket(8089, 3);
            //创建绑定到指定端口的服务器套接字
            while (true) {
                if (i <= 3) {
                    // 等待客户连接
                    Socket socket = server.accept(); //接收连接
                    System.out.println("第" + i + "个客户连接成功!");
                    new Thread(new ServerThread(socket, i)).start();
                    i++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        new StringServer().service();
    }
}

2.1.2ServerThread类

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class ServerThread implements Runnable {
    private int index;
    private Socket socket;
    public ServerThread(Socket socket, int i) {
        this.socket = socket;
        this.index = i;
    } // 任务是为一个用户提供服务
    @Override
    public void run() {
        try {
            try {
                // 读取客户端传过来信息的DataInputStream
                DataInputStream in = new DataInputStream(socket.getInputStream());
                // 向客户端发送信息的DataOutputStream
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                while (true) {
                    // 读取来自客户端的信息
                    String accpet = in.readUTF();
                    System.out.println("第" + index + "个客户端发出消息:" + accpet);
                    System.out.print("回复第" + index + "个客户端发出消息:");
                    Scanner scanner = new Scanner(System.in);
                    String send = scanner.nextLine();
                    out.writeUTF("服务器端回复您:" + send);
                }
            } catch (EOFException e) {
                //写触发异常 对方关闭连接 我却还在写
                System.out.println("对方关闭连接了");
            } finally {
                // 建立连接失败的话不会执行socket.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2客户端

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Random;
import java.util.Scanner;
//客户端
public class StringClient {
    private String name = String.valueOf(new Random().nextInt(999999));//客户端的名字
    public void chat() {
        try {
            // 连接到服务器
            Socket socket = new Socket("127.0.0.1", 8089);//在cmd里 ipconfig/all 查看本机ip
            // 读取服务器端传过来信息的DataInputStream
            DataInputStream in = new DataInputStream(socket.getInputStream());
            // 向服务器端发送信息的DataOutputStream
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
            // 装饰标准输入流,用于从控制台输入
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print("请输入数据:");
                if (!scanner.hasNext()) {
                    break; //输入完成
                }
                String send = scanner.nextLine();
                // 把从控制台得到的信息传送给服务器
                out.writeUTF("客户端[" + name + "]:" + send);
                // 读取来自服务器的信息
                String accpet = in.readUTF();
                System.out.println(accpet);
            }
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        new StringClient().chat();
    }
}

3.Socket相关概念

3.1Socket的概念

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

一个Socket是一对IP地址和端口

Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中。

生成套接字,主要有3个参数:通信的目的IP地址使用的传输层协议(TCP或UDP)和使用的端口号。Socket原意是“插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

3.2Socket的基本实现原理

实现方式:要通过互联网进行通信,至少需要一对套接字,一个运行于客户机端,称之为clientSocket,另一个运行于服务器端,称为serverSocket。

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

3.3Socket与TCP/IP的关系

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

Socket则是对TCP/IP协议的封装和应用(程序员层面上)。也可以说,TCP/IP协议是传输层协议,主要解决数据 如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:
“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也 可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”

我们平时说的最多的socket是什么呢,实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。 实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现 只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、 listen、connect、accept、send、read和write等等。网络有一段关于socket和TCP/IP协议关系的说法比较容易理解:
TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”

实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。Socket是对端口通信开发的工具,它要更底层一些。

3.4Socket与HTTP的关系

由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

发布了70 篇原创文章 · 获赞 3 · 访问量 1235

猜你喜欢

转载自blog.csdn.net/qq_43361209/article/details/103987668