Simple network chat program uses the ubuntu system python3

This is my second blog, first blog unfortunately did not get the recognition they deserve.

Probably because not enough Introduce the principle and practical operation of part, but simply analyzed during opening page, change the output of a particular instruction.

In my second blog in the relevant principles described in more detail, at the same time enriching the introduction of program code section.

In this paper, communication-related knowledge (such as socket sockets, TCP / IP, HTTP protocol), the relationship between the hello / hi Internet chat program code, python socke interfaces with Linux socket api three have done a related presentations

 

First, the network communication of knowledge

First of all it must be clear, before we carry out network communications, must know the five kinds of information: the protocol port to connect to the protocol, IP address of the local host, protocol port, IP address of the remote host, remote process of local processes.

 

1.Socket socket

Before introducing the socket, you need to be clear, the socket is not some kind of network protocol, which is a network communication process endpoint abstract representation contains five kinds of information network communication be necessary.

Appear background : when the application-layer data communication via the transport layer, TCP will encounter problems while providing services for multiple concurrent application processes. Multiple TCP connections or multiple applications through the same process may require a TCP protocol port to transfer data.

Action : The application layer and the transport layer socket interface, a communication process or to distinguish between different applications from a network connection, data transmission is concurrent services.

Socket establish a socket connection requires at least one pair, one running on the client, called the ClientSocket, another run on the server, called ServerSocket.

Socket connection process between the three steps: monitor server, client requests, connection confirmation. You need to enter through the three-way handshake.

Socket basic communication model :

Three-way handshake flow chart :

 

 

2.TCP / IP protocol

Before the introduction of the agreement need to sort out a concept: TCP / IP is not simply refers to the TCP protocol, which is the sum of a series of network protocols, the Internet is the core protocol.

基于TCP/IP的参考模型将协议分为四个层次:链路层、网络层、传输层、应用层。

TCP/IP协议族层层封装,最上面的是应用层,里面有HTTP、FTP等协议;第二层是传输层,我们熟知的TCP/UDP协议就位于该层中;、

第三层是网络层,里面的IP协议负责对数据加上IP地址和其他的数。据以确定传输的目标;

第四层是数据链路层,这个层次为待传送的协议加入一个以太网协议头,并进行CRC编码,为最后的数据传输做准备

下图为一个完整的数据封装过程:

 

3.TCP连接

它是传输层的一种传输控制协议,与之对应的有UDP连接。

TCP、UDP的区别:

(1).TCP面向连接的场景,通信前双方必须先建立连接;而UDP是无连接的通信,直接将数据发送给对应主机。

(2).TCP有滑动窗口、差错控制等来提供可靠的服务,传输的数据无差错、不丢失、不重复、按序到达;UDP不保证可靠交付。

(3).TCP占用系统资源多、实时性差;UDP反之。

真实场景举例:

我们使用的qq、微信发送消息时,采用的都是UDP连接。我们发送消息时对方并不知道你要发送消息给他。

使用qq发送文件或压缩包数据时,会有两种选项,离线发送对应的即是UDP连接;但在线发送需要对方确认接收后才能将数据包发送过去,此为TCP连接。

通常情况下,Socket连接就是TCP连接,本实验也是基于TCP连接做的网络通信。

 

4.HTTP协议

HTTP协议是手机应用上最广泛的协议,它可以通过传输层的TCP协议在客户端和服务器端之间进行数据以及数据之间的交互。

一个HTTP请求报文由请求行、请求头部、空行和请求数据4个部分组成。

HTTP请求报文格式如下:

网上关于HTTP的介绍特别多,我这里给大家分析一个最常见的应用场景,在浏览网页时,大家经常会碰到一些错误码,最常见的像404,这些都是HTTP的响应报文中的状态码

常见网页浏览状态码如下:

 

关于网络通信的知识就讲解到这,没有进行过多的分析,但想必大家对网络通信是个啥,有哪些常见的通信协议应该有了个大致的了解。

若大家对某一块想要深入了解,网上有很多资料可供大家选择。

 

二、python--hello/hi网络聊天程序

 

在本地linux系统实现基于tcp的网络通信,服务端程序监听本地ip地址127.0.0.1,监听端口号为6666。客户端程序向本机该端口号发送消息。

鉴于python对socket通信api封装的很好,整个代码过程并不多,主要分析代码函数。

程序代码如下:

client.py:客户端代码

import socket
import sys

# 创建一个socket套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 与对应的ip地址端口号建立连接
s.connect(('127.0.0.1', 6666))
while True:
    #发送数据:
    try:
        data = input("客户端:")
        s.send(data.encode())
        buf = s.recv(1024).decode()
        if buf != 'exit':
            print("服务端: " + buf)
    except:
        print("Dialogue Over")
        s.close()
        sys.exit(0)

Server.py:服务端代码

import socket
# 创建一个socket套接字,参数类型需要和client一致
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 监听端口
s.bind(('127.0.0.1', 6666))  
# 调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量
s.listen(1)  
sock, addr = s.accept()
buf = sock.recv(1024).decode()
while True:
    if buf != 'exit':
        print("客户端: " + buf)
    data = input("服务端: ")
    sock.send(data.encode())
    if data == 'exit':
        break
    buf = sock.recv(1024).decode()

运行效果图:注意需要先运行server端的代码,不然程序会报错。

关键函数socket函数api解释:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM):socket.AF_INET代表使用IPV4通信,流式套接字SOCK_STREAM。

s.bind(('127.0.0.1', 6666)):绑定主机名(127.0.0.1)、端口号(6666)

s.connect(('127.0.0.1', 6666)):连接到指定socket的服务器

s.listen(1):开始监听客户端发来的消息,最大监听数量为1

sock, addr = s.accept() :接受TCP连接并返回:conn 和 address

conn:新的套接字对象,可以用来接收和发送数据;address是连接客户端的地址。

sock.send(data.encode()):发送TCP数据,将参数中的数据发送到连接的套接字。

buf = sock.recv(1024).decode():接受TCP套接字的数据。数据以字符串形式返回,指定要接收的最大数据量为1024。

s.close():关闭套接字,即中断了一次连接。

由以上可以看出tcp连接是长期连接,一次建立连接后,双方可以互相发送消息。而对应的HTTP是短连接,客户端发送请求后,便断开了和服务器的连接。

 

三、python socke接口与Linux socket api之间的关系

Linux的一个哲学:所有的东西都是文件。socket也不例外,可读,可写,可控制,可关闭的文件描述符。

Python socket相关api函数在Linux socket api 中的对应关系:

(1)创建socket套接字

python中使用s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 创建。

Linux socket系统调用创建一个socket方式如下

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type, int protocol);

函数说明:
创建一个sockfd,以文件描述符的形式作为网络实体抽象的操作接口,包括unix domain socket, internet domain socket等不同场景下,可以按照文件读写方式来收发数据。
参数说明:
    domain 表示使用何种底层协议族 , 比如PF_UNIX(alias PF_LOCAL, Unix domain socket),PF_INET (TCP/IPv4),PF_INET6 (TCP/IPv6)等。由于历史原因,地址族AF_*(包括AF_LOCAL)通常作为实际使用,AF_* 与PF_*对应同值;
    type 表示指定服务类型,主要有SOCK_STREAM(TCP流服务)和SOCK_DGRAM(UDP数据报)等服务;
    protocol 表示在前两个参数确定的协议集合下,进一步确认具体传输协议,比如:IPPROTO_TCP、IPPROTO_UDP等。由于前两个参数已经给出了足够的信息,该参数已经确定,因此通常该参数置为0即可。
返回值:
​ 成功返回socket文件描述符;失败返回 -1, 并设置errno。

 

(2)绑定主机的套接字

python中使用s.bind(('127.0.0.1', 6666))来绑定。

Linux socket系统调用创建一个socket方式如下

 

   #include <sys/types.h>
   #include <sys/socket.h>
   int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);

 

函数说明:
​将一个socket地址绑定到socket文件描述符上。客户端socket文件描述符通常不需要绑定socket地址,采用匿名方式即可。
参数说明:
    sockfd 表示需要命名(绑定)的目标socket文件描述符;
    my_addr 表示将socket地址绑定至sockfd,即命名该sockfd;
    addrlen 表示该地址的长度。
返回值:
​成功时返回0, 失败时返回-1并设置errno, 常见的errno如下:
    EACCES 被绑定的地址是受保护的地址(知名服务器端口:0~1023),仅超级用户能够访问;
    EADDRINUSE 被绑定的地址正在使用中,比如将socket绑定到一个处于TIME_WAIT状态的socket地址。

 

(3)开启监听

python中使用s.listen(1)来监听,1为最大监听数。

Linux socket系统调用创建一个socket方式如下:

函数说明:
​ 在内核创建最大长度为backlog的监听队列。
参数说明:
    sockfd 表示创建的socket 文件描述符;
    backlog 表示提示内核监听队列中处于完全连接状态(ESTABLISHED)socket的最大长度,而半连接状态(SYN_RCVD)socket队列的最大长度定义在/proc/sys/net/ipv4/tcp_max_syn_backlog,若队列满,则peer客户端(connect())将收到ECONNREFUSED。
返回值:
​成功时返回0, 失败则返回-1, 并设置errno。常见的errno如下:
    EADDRINUSE 已有其他socket监听该port. 当未命名sockfd时(极罕见,例RPC,客户端通过端口映射器获取到临时端口完成建立连接),通常会从/proc/sys/net/ipv4/ip_local_port_range端口范围内获取临时端口,会发生临时端口范围内的端口都被使用,此时返回该错。

本文章主要对这三个Linux socket api 进行了分析,要想了解更多,可参考链接:https://blog.csdn.net/alpslover/article/details/80387140

此外,可使用strace python server.py命令跟踪这个程序所使用的系统调用

 

最后,我的上一篇博客正好介绍了Netstat命令,该命令可以用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。

要想熟悉该命令,可详细参考我的上一篇博客。

 

 

 

Guess you like

Origin www.cnblogs.com/xiaofengustc/p/12012638.html