Socket - TCP编程
Socket是网络编程的一个抽象概念。
通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可
socket参数及常用功能函数:
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) #创建socket对象
socket families(地址簇):
AF_UNIX —————————— unix本机之间进行通信
AF_INET —————————— 使用IPv4
AF_INET6 —————————— 使用IPv6
socket types:
SOCK_STREAM # TCP套接字类型
SOCK_DGRAM # UDP套接字类型
SOCK_RAW #原始套接字类型,这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧
SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
注:这些常量都是套接字类型,应用于socket()
函数中的第二个参数中.根据系统的不同,可能有更多的常数。(只有SOCK_STREAM
和SOCK_DGRAM
似乎通常很有用。)
协议号通常为零,可以省略,或者在地址族为AF_CAN
的情况下,协议应为CAN_RAW
或CAN_BCM
。如果指定fileno,则忽略其他参数,从而导致具有指定文件描述器的套接字返回。与socket.fromfd()
不同,fileno将返回相同的套接字,而不是重复。这可能有助于使用socket.close()
关闭分离的套接字,一般情况下后两个参数忽略即可。
socket.bind(address) #将socket绑定到地址(常用于服务端)
address地址的格式取决于地址族, 在AF_INET下,以元组(host,port)的形式表示地址。
socket.listen([backlog]) #启用服务器以接受连接(常用于服务端)。
backlog >=0,指定系统在拒绝新连接之前将允许的未接受连接的数量。如果未指定,则选择默认的合理值。
socket.accept() #接收一个连接.该socket 必须要绑定一个地址和监听连接.返回值是一对(conn,address)。(常用于服务端)
conn是socket对象,可以在该连接上发送和接收数据,address是连接另一端的地址。
socket.recv(bufsize[, flags]) #从socket接收数据,返回值是一个代表所收到的数据的字节对象。
一次性接收的最大数据量由bufsize指定, 参数flags通常忽略。
socket.send(data[, flags]) #将数据发送到socket。
python3中只能发送bytes类型的数据。
socket.connect(address) #连接到远程socket(常用于客户端)
如果连接被信号中断,则该方法等待直到连接完成,或者如果信号处理程序没有引发异常并且套接字正在阻塞或者已经阻塞,则在超时时引入socket.timeout
超时。对于非阻塞套接字,如果连接被信号中断(或由信号处理程序引发的异常),则该方法引发InterruptedError
异常。
socket.close() #关闭socket
注:被调用后,连接断开,socket不能在发送数据,连接另一端也将不在接收数据。
服务器
服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Socket连接了。
所以,服务器会打开固定端口(比如80)监听,每来一个客户端连接,就创建该Socket连接。由于服务器会有大量来自客户端的连接,所以,服务器要能够区分一个Socket连接是和哪个客户端绑定的。一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket。
但是服务器还需要同时响应多个客户端的请求,所以,每个连接都需要一个新的进程或者新的线程来处理,否则,服务器一次就只能服务一个客户端了。
我们来编写一个简单的服务器程序,它接收客户端连接,把客户端发过来的字符串加上Hello
再发回去。
1 #coding=utf-8 2 ''' 3 Created on 2019年8月6日 4 5 @author: yanerfree 6 ''' 7 #服务端 8 import socket 9 import threading 10 import time 11 12 def handle_client(sock,addr): 13 print ('Accept new connection from %s:%s...' %addr) 14 sock.send('Welcome!'.encode())#send welcome to client 15 16 while True: 17 data = sock.recv(1024) 18 time.sleep(1) 19 print('接收到来自客户端的数据-%s-'%data) 20 if data == b'exit' or not data: 21 break 22 sock.send(b'hell0-%s'%data)# 23 sock.close() 24 print('Connection from %s:%s closed.' % addr) 25 26 address = ("localhost", 6666) #写明服务端要监听的地址,和端口号 27 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #生成一个ipv4 socket对象 28 server.bind(address) #用socket对象绑定要监听的地址和端口 29 server.listen() #开始监听 30 print('Waiting for connection ... ') 31 #接下来,服务器程序通过一个永久循环来接受来自客户端的连接,accept()会等待并返回一个客户端的连接: 32 while True: 33 #接收新的连接 34 sock,addr = server.accept() #等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式 35 ''' 36 Wait for an incoming connection. Return a new socket 37 representing the connection, and the address of the client. 38 ''' 39 # 创建新线程来处理TCP连接: 40 t = threading.Thread(target=handle_client, args=(sock,addr)) 41 t.start() 42 43 44
客户端
大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。
举个例子,当我们在浏览器中访问新浪时,我们自己的计算机就是客户端,浏览器会主动向新浪的服务器发起连接。如果一切顺利,新浪的服务器接受了我们的连接,一个TCP连接就建立起来的,后面的通信就是发送网页内容了。
1 #coding=utf-8 2 ''' 3 Created on 2019年8月7日 4 5 @author: yanerfree 6 ''' 7 import socket 8 9 address = ("localhost", 6666) #写明要连接的地址,和端口号 10 #创建一个socket, 11 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 #连接服务端 13 client.connect(address) 14 # 接收欢迎消息: 15 print(client.recv(1024)) 16 for data in ['Michael','', 'Tracy', 'Sarah']: 17 # 发送数据: 18 if data:#过滤空字符,如果为空会阻塞recv() 19 print('发送至服务端的数据:%s'%data) 20 client.send(data.encode())#byte类型发送 21 print ('接收到服务端的回复:%s'%client.recv(1024)) 22 client.send(b'exit')#退出 23 client.close()#关闭
参考:https://www.runoob.com/python/python-socket.html
https://www.liaoxuefeng.com/wiki/897692888725344/923056653167136