Python Socket网络编程(一)初识Socket和Socket初步使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/youand_me/article/details/83088428

前言

       本系列博客是笔者学习Python Socket的过程笔记,目的在于记录。其中的解释都为自己的见解,仅供参考,如有错误,还望指出。本篇博客是对Python Socket的初步了解和使用,大佛请移驾。

网络编程

  • 实质

       网络编程本质就是实现两个设备之间的数据交换(通信),通常这个设备指的是计算机,实际上任何能连接网络的硬件设备都能实现通信。也就是说我们的任何能连接网络的设备都是可通信的,比如我有一个 LED显示屏,我现在需要服务器控制这个 LED屏幕显示一段文字,一些轮播图片或者一个视频,并且控制设备什么时间播放什么内容,播放多长时间等命令。那么LED和我的服务器之间就需要通信,这个时候就不是计算机与计算机之间通信了。

       在网络编程中,发起连接的一方被称作客户端(Client),等待连接的一方被称作服务器(Server)。服务端一般都需要一直启动,等待客户端来连接。连接一旦建立,双方就可以互相发送数据了。

  • IP地址和端口

       网络通信和生活中的打电话类似,我要给某个人打电话我就得知道他的电话号码,在网络中也是如此,我要和服务器建立通信就需要知道服务器的在网络中的位置。计算机在网络中的位置由IP地址(具体概念查看IP百度百科)来区分标识。建议再看看私有IP和共有IP的区别。

       一台计算机上(设备)可以运行多个程序(多个进程),为了区分这些程序就设计了端口(Port)的概念。设备最多有216=65536个端口,一个端口可以对应一个唯一程序,无论是服务端还是客户端,每个程序都对应一个或多个端口。其中0-1024之间的大多端口已经被操作系统占用,我们的程序一般就使用之后的端口号(仅仅针对计算机设备)。也就是说通过IP和端口号就可以实现两个设备的某个程序之间进行通信了。

  • 数据传输协议

       对于建立了连接的两个设备以何种方式进行数据的传输呢,传输数据的方式无论是有线传输还是无线传输,一般就两种传输协议方式:

       1. TCP(Transfer Control Protocol)

       传输控制协议方式,该传输方式是一种稳定可靠的传送方式,类似于显示中的打电话。只需要建立一次连接,就可以多次传输数据。就像电话只需要拨一次号,就可以实现一直通话一样,如果你说的话不清楚,对方会要求你重复,保证传输的数据可靠。使用该种方式的优点是稳定可靠,缺点是建立连接和维持连接的代价高,传输速度不快。

       2. UDP(User Datagram Protocol)

扫描二维码关注公众号,回复: 3621988 查看本文章

       用户数据报协议方式,该传输方式不建立稳定的连接,类似于发短信息。每次发送数据都直接发送。发送多条短信,就需要多次输入对方的号码。该传输方式不可靠,数据有可能收不到,系统只保证尽力发送。使用该种方式的优点是开销小,传输速度快,缺点是数据有可能会丢失。

  • 协议

       协议(Protocol)在网络里是一个重要的概念,平时所说的协议实际就是指网络协议,网络协议就是设备实现通信的规定,双方必须遵守这个规定才能获取到正确的通信信息。比如在建立连接的时候应该何种方式连接,怎么互相判别,传输的数据格式(也就是要按照一定的格式来发送和接收数据)是什么。只有遵守这个规定,设备之间才能相互通信交流。它的三要素是:语法、语义、时序。
       为了使数据在网络上从源到达目的,网络通信的参与方必须遵循相同的规则,这套规则称为协议(protocol),它最终体现为在网络上传输的数据包的格式。

Socket

  • 概念

       Socket即是套接字,Python将低级别的网络服务封装成了一个模块,通过socket就可以将网络中的两个设备的某一进程(应用程序)以TCP或者UDP协议方式建立连接,在建立连接过后就可以实现设备进程与设备进程之间的通讯了。

  • 套接字

       我们导入socket(使用import socket)模块,使用s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)来创建返回一个基于IPv4地址流式TCP传输协议的套接字s,我们需要创建套接字最主要考虑前两个参数,第一个是IP地址簇,第二个是传输协议类型,下面列了常用的几个可选值,想要了解全部请前往Python3 socket

  1. family:IP地址簇参数
可选值 描述
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6
socket.AF_UNIX 用于Unix系统进程间通信
socket.AF_…
  1. type:类型参数
可选值 描述
socket.SOCK_STREAM 流式socket,TCP(默认)
socket.SOCK_DGRAM 数据报式socket,UDP
socket.SOCK_…
  • socket对象方法
函数 类型 描述
s.bind() 服务端用 绑定地址和端口到套接字,参数address为元组形式的(host, port)
s.listen() 服务端用 开始监听绑定的地址端口程序(进程),参数backlog指定在拒绝连接之前,可以挂起的最大连接数量。
s.accept() 服务端用 等待客户端的连接(阻塞式)。
s.connect() 客户端用 主动去连接服务器,参数address为元组形式的(host, port),如果连接出错,返回socket.error错误。
s.connect_ex() 客户端用 主动去连接服务器,参数address为元组形式的(host, port),出错时返回出错码,而不是抛出异常。
s.recv() 公共使用 接收数据,返回字节型字符串数据,参数bufsize指定接收数据的最大长度。
s.send() 公共使用 发送数据,返回发送成功的字节数,参数data是要发送的字节型字符串数据。
s.sendall() 公共使用 完整发送数据。内部循环调用send直至数据发送完整,参数data是要发送的字节型字符串数据。
s.recvfrom() 公共使用 接收数据,返回值是(data, address)。data是包含接收数据的字符串,address是发送数据的套接字地址。
s.sendto() 公共使用 发送数据,将数据发送到套接字,address形式为(host, port)的元组,指定远程地址。返回值是发送字节数。
s.close() 公共使用 关闭套接字
s.getpeername() 公共使用 返回连接套接字的远程地址。返回值通常是元组(host, port)。
s.getsockname() 公共使用 返回套接字自己的地址。通常是一个元组(host, port)。
s.setsockopt() 公共使用 设置给定套接字选项的值。
s.getsockopt() 公共使用 返回套接字选项的值。
s.settimeout() 公共使用 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。
s.gettimeout() 公共使用 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.fileno() 公共使用 接收数据,返回字节型字符串数据,参数bufsize指定接收数据的最大长度。
s.setblocking() 公共使用 flag为0非阻塞,否则为阻塞模式(默认)。非阻塞模式调recv()或send()没有数据,将引起socket.error异常。
s.makefile() 公共使用 创建一个与该套接字相关连的文件。

初步使用

  • 功能

       由于要实现的是两个进程间的通信(同一个设备),那么需要两个程序,我们分别叫客户端程序和服务端程序。
       在这个初级使用实例中,实现的是一台计算机中两个进程之间的通信(一个进程为等待客户端连接的服务端程序,一个进程为主动去连接服务端的客户端程序)。也就是说客户端和服务端程序都运行在本地的一台计算机上,服务端建立socket,监听本机IP的6688端口等待客户端来连接,一旦有一个客户端来连接了就打印连接信息,然后等待连接的客户端发送数据,接收到客户端传来的数据后,就反馈给客户端收到信息了;客户端程序先建立socket套接字,然后去连接本机的IP和6688端口进程,连接成功后等待控制台输入数据,接受到输入的数据后发送到服务端,然后结束连接。

  • 源码

       先新建一个server.py文件,这个文件里写服务端功能程序,如下:

import socket


# 创建一个socket套接字,该套接字还没有建立连接
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定监听端口
server.bind(('localhost', 6688))
# 开始监听,并设置最大连接数
server.listen(5)
# 获取未建立连接的服务端的IP和端口信息
print(server.getsockname())
# 下面注释掉的是获取未建立连接的服务端套接字的远程IP和端口信息,执行下面语句会报错,原因就是现在还没有远程客户端程序连接
# print(server.getpeername())

print(u'waiting for connect...')
# 等待连接,一旦有客户端连接后,返回一个建立了连接后的套接字和连接的客户端的IP和端口元组
connect, (host, port) = server.accept()
# 现在建立连接就可以获取这两个信息了,注意server和connect套接字的区别,一个是未建立连接的套接字,一个是已经和客户端建立了连接的套接字
peer_name = connect.getpeername()
sock_name = connect.getsockname()
print(u'the client %s:%s has connected.' % (host, port))
print('The peer name is %s and sock name is %s' % (peer_name, sock_name))

# 接受客户端的数据
data = connect.recv(1024)
# 发送数据给客户端告诉他接收到了
connect.sendall(b'your words has received.')
print(b'the client say:' + data)

# 结束socket
server.close()

       然后建立一个client.py文件,实现客户端程序,内容如下:

import socket


# 创建一个socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 主动去连接本机IP和端口号为6688的进程,localhost等效于127.0.0.1,也就是去连接本机端口为6688的进程
client.connect(('localhost', 6688))

# 接受控制台的输入
data = input()
# 对数据进行编码格式转换,不然报错
data = data.encode('utf-8')
# 发送数据
client.sendall(data)
# 接收服务端的反馈数据
rec_data = client.recv(1024)
print(b'form server receive:' + rec_data)

client.close()
  • 运行结果

在这里插入图片描述

       其中左边为服务端运行结果,右边为客户端运行结果,右边的hello是手动输入然后回车。

结语

       到此初步的使用已经差不多了,不过上述代码只能是一对一的通信,一对多不是本篇博客的内容,因为客户端一般都不会只有一个,所以这个一对一不能满足我们的常用需求,后面的博客将会介绍多线程实现多客户端连接服务器,与服务器通信。在下一篇博客会讲解和实现局域网内两台设备,广域网之间,局域网与广域网之间设备的通信。

下一篇:Python Socket网络编程(二)局域网内和局域网与广域网的持续通信

猜你喜欢

转载自blog.csdn.net/youand_me/article/details/83088428