単純なネットワークチャットプログラムは、Ubuntuのシステムのpython3を使用しています

これは私の第二のブログ、残念ながら彼らが値する認識を取得していない最初のブログです。

おそらくので、十分な一部の原理と実践的な操作を紹介していない、単にオープニングページ中に分析、特定の命令の出力を変更します。

関連する原則の私の第二のブログでは、プログラムコードのセクションの導入を豊か同時に、より詳細に説明。

この論文では、通信関連の知識は、ハロー/ HIインターネットチャット・プログラム・コードとの間の関係、(例えばソケットのソケット、TCP / IP、HTTPプロトコルなど)、LinuxのソケットAPI 3との界面socke Pythonは、関連するプレゼンテーションを行っています

 

まず、知識のネットワーク通信

私たちは情報の5種類を知っている必要があり、ネットワーク通信を行う前に、まず第一に、それは、明確でなければならない:プロトコルポート、プロトコル、ローカルホストのIPアドレス、プロトコル、ポート、リモートホスト、ローカルプロセスのリモートプロセスのIPアドレスに接続します。

 

1.Socketソケット

ソケットを導入する前に、あなたは明確にする必要があり、ソケットはネットワーク通信プロセスは、抽象表現は、情報ネットワーク通信の5種類が必要な場合が含まれているエンドポイントであるネットワークプロトコルのいくつかの種類ではありません。

背景に表示され:複数の並行アプリケーション・プロセスのためのサービスを提供しながら、トランスポート層を介してアプリケーション層のデータ通信を、TCPは、問題が発生します。同じプロセスを経て複数のTCP接続または複数のアプリケーションは、転送データにTCPプロトコルポートを必要とするかもしれません。

アクション:アプリケーション層とトランスポート層ソケットインタフェース、通信処理又はネットワーク接続から異なるアプリケーションの間で区別するために、データ伝送は同時サービスです。

ソケット接続は、クライアント上で実行されている、いずれかの少なくとも一つのペアを必要と確立ソケット、ServerSocketを呼ばClientSocket、サーバー上の別の実行を、と呼ばれます。

3つのステップ間のソケット接続プロセス:モニター・サーバー、クライアント要求、接続確認。あなたは、3ウェイハンドシェイクを通じて入力する必要があります。

ソケットの基本的な通信モデル

スリーウェイハンドシェイクのフローチャート

 

 

2.TCP / IPプロトコル

概念を整理することで合意の必要性を導入する前に:TCP / IPは、単にネットワークプロトコルの一連の和であるTCPプロトコルを意味していない、インターネットは、コアプロトコルです。

基于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协议相关的统计数据,一般用于检验本机各端口的网络连接情况。

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

 

 

 

おすすめ

転載: www.cnblogs.com/xiaofengustc/p/12012638.html