Python学习笔记--网络编程, socket

时间:2021-09-25 00:32:03

简介:

        百度百科上介绍说:Socket原意是 “插座”,可以看成是在两个程序进行通讯连接中的端点,是连接应用程序和网络驱动程序的桥梁。Socket在应用程序中创建,通过绑定与网络驱动建立关系。套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

        个人的理解:假设有一个有两个门的房间,这两个门都有各自的钥匙,且一个是面向服务器(server)的,另一个是面向客户(client)的,当服务器与客户分别拿到这两把钥匙时,二者就可以通过这个房间交换信息了。这对钥匙就相当于是一对socket,网络通路相当于是房间,但因为网络通路并不是只有一条,相当于存在无数个这样的房子,所以就有无数对这样的钥匙,这时每个socket应该有些信息来标注自己的身份,不然分不清了,与人们一般选择不同形状的钥匙一个道理。具体实现中socket使用了三种手段一起来为自己标注:一种是网络传输协议的种类(TCP or UDP),然后是对方的IP地址,最后是对方(客户端)或自己(服务器端)的端口号Port. 一旦服务器端与客户端的socket能配对上,则二者就可以通信了。

        这里简单说下TCP与UDP。TCP即传输控制协议(Transmission Control Protocol),是一种流套接字,是面向连接的,在通信之前,要建立并维持一条连接,直到通信结束,这种方式叫做“虚电路”,是一种可靠数据传输方式,通过握手机制保证数据传输的准确性。UDP即用户数据报协议(User Datagram Protocol),不需要在通信前提前建立一条连接,而在确定了合适大小的报文大小后,直接把数据放到网上,通过路由控制协议向目的地传输,不保证数据传输的正确性与顺序,速度比TCP快好多,广泛应用于视频音频等即时通信服务中。

        Python中使用socket模块进行client/server 网络编程。基于网络的socket有一个自己的address family name: AF_INET. socket模块可以选择TCP/UDP,目的地地址与端口,并有相关数据传输与接收函数。

实例:

由于是在同一台电脑上运行,所以开了两个Python: Python3.3(for server), Python3.2(for client)

TCP-服务器端:

from socket import*
from time import ctime

HOST='' #空表示可以接收多有有效ip地址的连接请求,bind()函数可以绑定在所有有效的ip地址上
PORT=8080 #随机选的一个端口号,必须大于1024
BUFSIZ=1024 #每次读取的数据量
ADDR=(HOST,PORT) #HOST与PORT共同组成了ADDR

tcpSerSock=socket(AF_INET, SOCK_STREAM) #创建了一个基于网络的、使用TCP的socket。AF_INET表示是基于网络的socket编程,SOCK_STREAM表示是TCP通信
tcpSerSock.bind(ADDR) #socket与ADDR绑定到一起,表示socket可以在这个PORT上接收HOST处的连接请求。还需要开始监听
tcpSerSock.listen(5) #开始监听,5表示同时最多可以有5个连接进来。开始等待连接到来

while True: #表示一直等待
print("waiting for connecting...")
(tcpCliSock,addr)=tcpSerSock.accept() #如果有连接进来,则生成一个新的socket: tcpCliSock,并得到源的地址
print('...connected from: ',addr)

while True: #开始接收数据,并处理
data=tcpCliSock.recv(BUFSIZ).decode('utf8') #接收数据,并转化成utf-8格式,原始的是bytes格式
if not data: #如果没有数据了,则跳出while循环,等待下一次连接到来
break;
print('[%s] %s'%(ctime(),data)) #向shell输出,增加了当前的时间
tcpCliSock.send(('[%s] %s'%(ctime(),data)).encode('utf8')) #将数据转换成bytes型,再send回去

tcpCliSock.close() #关闭tcpCliSock,一次通信在服务器端的工作完成,继续等待下一次连接的到来
tcpSerSock.close() #不会被执行到,可以加个try-except进去,让程序更友好

TCP-客户端:

from socket import*

HOST='localhost' #由于是在同一台电脑上,所以可以写localhost,如果是在两台电脑上,则这儿要写server的ip地址
PORT=8080
BUFSIZ=1024
ADDR=(HOST,PORT) #服务器的ADDR

tcpCliSock=socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR) #连接到服务器,成功后,服务器端输出'...coonnected from...'

while True:
data=input('> ').encode('utf8')
if not data: #直接敲回车,则跳出while循环
break;
tcpCliSock.send(data)
data=tcpCliSock.recv(BUFSIZ)
if not data:
break;
print(data.decode('utf8'))
tcpCliSock.close()


        服务器端将bytes格式转换成utf-8格式,而客户端不需要的原因是,客户端没有对数据进行处理,直接输出;而服务器端在原数据基础上增加了当前的时间,所以转换成uft-8格式,便于处理。utf-8是unicode,可以处理汉语。

TCP-通信结果:

>>> 
waiting for connecting... #先运行服务器,等待客户端的运行
...connected from: ('127.0.0.1', 53808) #当客户端运行,则出现这一行,同时客户端出现'> '
[Wed Aug 14 20:50:19 2013] Python编程 #输出处理后的结果
waiting for connecting... #一轮通信完成,等待下一轮的到来

>>>
> Python编程 #向服务器端发送数据:'Python编程'
[Wed Aug 14 20:50:19 2013] Python编程 #得到服务器端的反馈
> #结束
>>>

UDP-服务器端:(与TCP大同小异)

from socket import *
from time import ctime

HOST=''
PORT=8080
BUFSIZ=1024
ADDR=(HOST,PORT)

udpSerSock=socket(AF_INET,SOCK_DGRAM) #SOCK_DGRAM表示是UDP通信
udpSerSock.bind(ADDR) #绑定到ADDR,由于没有'虚电路',无连接,所以不需要listen,只是被动等待数据到来

while True: #被动等待数据到来
print('waiting for message...')
(data,addr)=udpSerSock.recvfrom(BUFSIZ) #当有数据到来时,得到data与源addr。注意这里不能产生一个新的socket,因为UDP是无连接的
data=data.decode('utf8') #bytes转换成utf-8
udpSerSock.sendto(('[%s] %s'%(ctime(),data)).encode('utf8'),addr) #传输处理后的数据,需要写addr,仍然因为是无连接
print('...received from and returned to:',addr)

udpSerSock.close()

UDP-客户端:

from socket import*

HOST='localhost'
PORT=8080
BUFSIZ=1024
ADDR=(HOST,PORT)

udpCliSock=socket(AF_INET,SOCK_DGRAM) #SOCK_DGRAM表示UDP通信

while True:
data=input('> ').encode('utf8')
if not data:
break;
udpCliSock.sendto(data,ADDR)
(data,ADDR)=udpCliSock.recvfrom(BUFSIZ) #可以得到ADDR
if not data:
break;
print(data.decode('utf8'))

udpCliSock.close()

UDP-通信结果:

>>> 
waiting for message...
...received from and returned to: ('127.0.0.1', 56259)
waiting for message...

>>>
> Python编程
[Wed Aug 14 20:53:39 2013] Python编程
>
>>>