Python 中的TCP服务器网络编程
TCP服务器端:
import socketimport threading
serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 这里的 AF_INET和SOCK_STREAM 指的是 TCP服务器
serversocket.bind(("127.0.0.1",8888))
# 绑定服务地址和端口号
serversocket.listen(5)
# 最多同时连接5个客户
c = serversocket.accept()
# 接收客户端的连接,此c是元组,表示得到的客户端的一些信息
print("服务器已连接...")
def myrerv(c):#这个函数用来接收
while True:
msg = c[0].recv(1024)
#用来接收信息
print(msg.decode())
#用来信息解码
threading._start_new_thread(myrerv,(c,))# 启动线程
def myinput():#这个函数用来发送
while True:
msg = input()
#写信息
c[0].send(msg.encode())
#信息编码
threading._start_new_thread(myinput())
TCP群聊服务端
import socketimport threading
serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serversocket.bind(("127.0.0.1",8888)) #绑定服务器地址和端口号
serversocket.listen(5) # 最多同时接收5个
print("服务器已连接...")
msg = None #定义一个全局的变量,用来存储聊天信息,临时存储当前抢到线程的数据
#设定锁
lock = threading.Lock()
mythread = threading.Condition(lock)
def server_recv(c,a): #接收信息
global msg #获取全局变量
while True:
mystr = c.recv(1024)
mythread.acquire() # 获取锁 线程同步
msg = str(a) + mystr.decode() # 信息解码
print(msg)
mythread.notify_all() # 通知解锁
mythread.release() # 所释放
def server_send(c,a): #发送信息
global msg #获取全局变量
while True:
mythread.acquire() #获取锁
mythread.wait() #等待
mythread.release() #释放
c.send(msg.encode()) #信息编码
print(msg)
while True:
c,a = serversocket.accept()
threading._start_new_thread(server_recv,(c,a)) #起到接收线程
threading._start_new_thread(server_send,(c,a)) #起到发送线程
TCP客户端:
import socketimport threading
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8888))
# 这里的地址和端口要和服务器的相同
print("已连接服务器...")
def myrerv(c):#接收信息
while True:
msg = c.recv(1024)
print(msg.decode())
#信息解码
threading._start_new_thread(myrerv,(client,)))# 启动线程
def myinput():#发送信息
while True:
msg = input()
client.send(msg.encode())
#信息编码
threading._start_new_thread(myinput())
socket()模块函数
要创建套接字,必须使用socket.socket()函数,它的一般语法如下:socket(socket_family,socket_type,protocol=0)
其中,socket_family是 AF_UNIX或AF_INET(如前所述),socket_type是SOCK_STREAM
或SOCK_DGRAM(如前所述)。protocol通常省略,默认为0.
所以,为了创建TCP/IP套接字,可以用下面的方式调用socket.socket()
tcpSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
同样,为了创建UDP/IP套接字,需要执行以下语句
udpSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
因为有很多socket模块属性,所有此时使用"from module import *" 这种导入方式可以
接受,不过这只是其中的一个例外。如果使用"from socket inport *",那么我们就把socket
属性引入到命名空间中,虽然这看起来有些麻烦,但是通过这种方式将能够大大缩短代码,
正如下面所示。
tcSock = socket(AF_INET,SOCK_STREAM)
一旦有了一个套接字对象,那么使用套接字对象的方法将可以进行进一步的交互
套接字对象(内置)方法
名称 描述服务器套接字方法
s.bind() |将地址(主机名,端口号对)绑定到套接字上
s.listen() |设置并启动TCP监听器
s.accept() |被动接受TCP客户端连接,一直等待直到连接到达(阻塞)
客户端套接字方法
s.connect() |主动发起TCP服务器连接
s.connect_ex() |connect()的扩展版本,此时会以错误码的形式返回问题,而不是抛出一个异常
普通的套接字方法
s.recv() |接收TCP消息
s.recv_into() |接收TCP消息到指定的缓冲区
s.send() |发送TCP消息
s.sendall() |完整地发送TCP消息
s.recvfrom() |接收UDP消息
s.recvfrom_into() |接收UDP消息到指定的缓冲区
s.sendto() |发送UDP消息
s.getpeername() |连接到套接字(TCP)的远程地址
s.getsockname() |当前套接字的地址
s.getsockopt() |返回给定套接字选项的值
s.setsockopt() |设置给定套接字选项的值
s.shutdown() |关闭连接
s.close() |关闭套接字
s.detach() |在未关闭文件描述符的情况下关闭套接字,返回文件描述符
s.ioctl() |控制套接字的模式(仅支持Windows)
面向阻塞的套接字方法
s.setblocking() |设置套接字的阻塞或非阻塞模式
s.settimeout() |设置阻塞套接字操作的超时时间
s.gettimeout() |获取阻塞套接字操作的超时时间
面向文件的套接字方法
s.fileno() |套接字的文件描述符
s.makefile() |创建与套接字关联的文件对象
数据属性
s.family() |套接字家族
s.type() |套接字类型
s.proto() |套接字协议