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

前言

       本系列博客是笔者学习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)

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

  • 协议

       协议(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_INETIPv4(默认)
socket.AF_INET6IPv6
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网络编程(二)局域网内和局域网与广域网的持续通信

  • 12
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值