ubuntu系统下使用python3实现简单的网络聊天程序

这是我的第二篇博客,很遗憾第一篇博客没有得到应有的认可。

可能是因为原理介绍和实操部分不够多,只是单纯分析了某一条指令在打开网页过程中,输出的变化。

在我的第二篇博客中把相关原理介绍的更加详细了,同时丰富了程序代码部分的介绍。

本文对通信相关知识点(如socket套接字、TCP/IP、HTTP通信协议)、hello/hi网络聊天程序代码、python socke接口与Linux socket api之间的关系三个方面做了相关介绍

一、网络通信相关知识

首先必须明确一点,我们进行网络通信之前,必须知道五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地址、远程进程的协议端口。

1.Socket套接字

在介绍套接字之前,需要明确一点,套接字并不是某种网络协议,它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息。

出现背景:应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。

作用:应用层可以和传输层通过socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。

套接字之间的连接过程分为三个步骤:服务器监听、客户端请求、连接确认。需要进过三次握手。

Socket基本通信模型:

三次握手流程图:

2.TCP/IP协议

在介绍该协议之前需要理清一个概念:TCP/IP并不是单纯的指TCP协议,它是一系列网络协议的总和,是Internet的核心协议。

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

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

原文地址:https://www.cnblogs.com/xiaofengustc/p/12012638.html

时间: 2024-10-11 21:25:45

ubuntu系统下使用python3实现简单的网络聊天程序的相关文章

java实现hello/hi的简单的网络聊天程序与ServerSocket调用栈跟踪

java实现hello/hi的简单的网络聊天程序 网络聊天采用TCP协议通过java实现 import java.io.*; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception{ Socket socket = new Socket("192.168.31.68", 6666); BufferedReader reader = new

以您熟悉的编程语言为例完成一个hello/hi的简单的网络聊天程序

在这片博文我们将使用python完成一个hello/hi的简单的网络聊天程序 先做一下准备工作 1.linux的socket基础api: 使用socket()创建套接字 int socket(int af, int type, int protocol); af为IP地址类型,AF_INE和AF_INET6分别对应ipv4和ipv6地址type是数据传输方式,Sock_stream(面向连接套接字)和sock_dgram(无连接套接字)protocol是传输协议,IPPROTO_TCP和IPPR

基于Python完成一个hello/hi的简单的网络聊天程序

一.Socket 套接字简介 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 传输层实现端到端的通信,因此,每一个传输层连接有两个端点.那么,传输层连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口.传输层连接的端点叫做套接字(socket).根据RFC793的定义:端口号拼接到IP

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

1.Socket概述 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点.通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到

一个hello/hi的简单的网络聊天程序

我选择使用python来实现hello/hi的简单网络聊天程序,源代码包括两个部分,客户端代码和服务器端代码,源代码部分如下图所示: 服务器端代码 1 import socket 2 3 HOST = '127.0.0.1' 4 PORT = 8888 5 6 server = socket.socket() 7 server.bind((HOST, PORT)) 8 server.listen(1) 9 10 print(f'the server is listening at {HOST}:

python实现一个简单的网络聊天程序

一.Linux Socket 1.Linux Socke基本上就是BSD Socket(伯克利套接字) 伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信.BSD Socket的应用编程接口已经是网络套接字的抽象标准.大多数其他程序语言使用一种相似的编程接口.由于伯克利套接字是第一个socket,大多数程序员很熟悉它们,所以大量系统把伯克利套接字作为其主要的网络API. 主要的头文件如下,不同的系统可能具体不同. <sys/socket.h> BSD

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

一.TCP/IP协议通信原理 TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件.软件需求的定义.TCP/IP协议确切的说法应该是TCP/UDP/IP协议.UDP协议(User Datagram Protocol 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输.TCP协议(Transmission Control Protocol 传输控制协议),是一种流传输的协议.他提供可靠的.有序的.双向的.面向连接的传输. 保护消息边界,就是指传输协议把数据当作一条独立的消

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

在这篇文章中,我将先简要介绍socket原理,然后给出一个利用Python实现的简单通信样例,最后通过跟踪系统调用来分析Python中socket函数与Linux系统调用的对应关系. 1.socket简介 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议.下图为原理图: 2.简单通信样例

实现一个的简单的网络聊天程序

本次实验采用Java语言,编写了一个简单的聊天室程序,可以实现多人之间的聊天.以下将对该程序进行详尽分析,并对比分析该编程语言提供的网络接口API与Linux Socket API之间的关系. 1. 网络通信相关要素 1) 协议 通信的协议还是比较复杂的, java.net 包中包含的类和接口,它们提供低层次的通信细节.我们可以直接使用这 些类和接口,来专注于网络程序开发,而不用考虑通信的细节. java.net 包中提供了两种常见的网络协议的支持: TCP:传输控制协议 (Transmissi