使用python实现一个hello/hi的简单的网络聊天程序

LandryBean 2019-12-10

一、TCP/IP协议通信原理

   TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件、软件需求的定义。TCP/IP协议确切的说法应该是TCP/UDP/IP协议。UDP协议(User Datagram Protocol 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输。TCP协议(Transmission Control Protocol 传输控制协议),是一种流传输的协议。他提供可靠的、有序的、双向的、面向连接的传输。
        保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。
        而面向流则是指无保护消息边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包。
        举例来说,假如,我们连续发送三个数据包,大小分别是2k、4k、8k,这三个数据包都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完。而使用TCP协议,我们只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。
        这就是因为UDP协议的保护消息边界使得每一个消息都是独立的。而流传输,却把数据当作一串数据流,它不认为数据是一个一个的消息。所以有很多人在使用TCP协议通讯的时候,并不清楚TCP是基于流的传输,当连续发送数据的时候,他们时常会认为TCP会丢包。其实不然,因为当它们使用的缓冲区足够大时,它们有可能会一次接收到两个甚至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个数据包,而已经接收的其它据包却被忽略了。

使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务器端和客户端两部分,其主要实现过程如下图所示:

使用python实现一个hello/hi的简单的网络聊天程序

(1)连接建立:服务器调用socket()、 bind()、 listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。

(2)数据传输:建立连接后, TCP协议提供全双工的通信服务,但是一般的客户端/服务器程序的流程是由客户端主动发起请求,服务器被动处理请求,一问一答的方式。因此,服务器从accept()返回后立刻调用read(),读socket就像读管道一样,如果没有数据到达就阻塞等待,这时客户端调用write()发送请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此期间客户端调用read()阻塞等待服务器的应答,服务器调用write()将处理结果发回给客户端,再次调用read()阻塞等待下一条请求,客户端收到后从read()返回,发送下一条请求,如此循环下去。

(3)关闭连接:如果客户端没有更多的请求了,就调用close()关闭连接,就像写端关闭的管道一样,服务器的read()返回0,这样服务器就知道客户端关闭了连接,也调用close()关闭连接。注意,任何一方调用close()后,连接的两个传输方向都关闭,不能再发送数据了。如果一方调用shutdown()则连接处于半关闭状态,仍可接收对方发来的数据。

二、JavaSocket

Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。抽象类SocketImpl是实现套接字的所有类的通用超类。创建客户端和服务器套接字都可以使用它。

socket()调用过程如下:

使用python实现一个hello/hi的简单的网络聊天程序

 三、基于java的socket编程

客户端:

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 简易在线聊天程序客户端
 */
public class client {
    public static void main(String[]args) throws UnknownHostException, IOException{
        System.out.println("---client---");
        //连接建立,使用Socket创建客户端,这里要注意端口号要跟本地其它已经写过的网络程序相区分开
        Socket client =new Socket("localhost",666);
        //客户端发送消息
        BufferedReader console=new BufferedReader(new InputStreamReader(System.in));
        String msg = console.readLine();
        DataOutputStream dos= new DataOutputStream(client.getOutputStream());
        dos.writeUTF(msg);
        dos.flush();
        //接收消息
        DataInputStream dis = new DataInputStream(client.getInputStream());
        msg = dis.readUTF();
        System.out.println(msg);
        //释放资源
        dos.close();
        dis.close();
        client.close();
        }
}

服务端:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 简易在线聊天程序服务端
 */
public class server {
    public static void main(String[]args) throws UnknownHostException,IOException{
        System.out.println("---server---");
        //指定端口 使用ServerSocket创建服务器
        ServerSocket server = new ServerSocket(666);
        //阻塞式等待连接
        Socket client = server.accept();
        System.out.println("一个客户端连接建立");
        //接收消息
        DataInputStream dis = new DataInputStream(client.getInputStream());
        String msg = dis.readUTF();
        System.out.println("client say:"+msg);
        //返回消息
        DataOutputStream dos= new DataOutputStream(client.getOutputStream());
        dos.writeUTF(msg);
        //释放资源
        dos.flush();
        dos.close();
        dis.close();
        client.close();
    }
}

实验结果:

使用python实现一个hello/hi的简单的网络聊天程序

 使用python实现一个hello/hi的简单的网络聊天程序

相关推荐