python的socket的tcp_Python之socket_tcp

1.1socket编程之tcp编程

"""

socket类型

sock_stream 面向连接的流套接字,默认值 tcp协议

sock_dgram 无连接的数据报文套接字,udp协议

"""

import socket

s = socket.socket()

s.bind(('127.0.0.1',9999)) #bind接受一个2元祖

s.listen()

"""

Accept a connection. The socket must be bound to an address and listening for connections.

The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection,

and address is the address bound to the socket on the other end of the connection

"""

new_socker,info = s.accept() #只接受一个client请求,阻塞

data=new_socker.recv(1024)  #阻塞

print(data)

print(type(data))

new_socker.send('back {}'.format(data).encode())

s.close()

例子

有阻塞就要尽量放到线程中去执行,不要影响主线程

importsocket

server=socket.socket()

server.bind(('127.0.0.1',9999))

server.listen()'''建立一个client,socket连接之后,只能发一次数据

在accept出阻塞,需要建立第二个连接'''

whileTrue:

new_socket,ip=server.accept()

data= new_socket.recv(1024)

new_socket.send('ck test {}'.format(data).encode())

socket群聊实例

importsocketimportthreadingclassChatTcpServer:def __init__(self,ip,port):

self.ip=ip

self.port=port

self.cliets={}#实例化就创建一个socket对象

self.socket =socket.socket()defstart(self):

self.socket.bind((self.ip,self.port))

self.socket.listen()

threading.Thread(target=self._accept,name="_aceept").start()def _accept(self): #只开启一个accept线程,连接产生的new_socket负责和线程receive同信

whileTrue:print('1~~~~~~~~~~~~~~~~~~~',threading.enumerate())

new_socket,raddr= self.socket.accept() #阻塞主线程,所以开启一个工作线程receive

threading.Thread(target=self._receive,name="reveive",args=(new_socket,)).start()

self.cliets[new_socket]=raddrprint(self.cliets)print(type(self.cliets.keys()))def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程

whileTrue:print('2~~~~~~~~~~~~~~~~~~~',threading.enumerate())

data= new_socket.recv(1024) #阻塞

for k inself.cliets.keys():

k.send('ack {}'.format(data).encode())defstop(self):for s inself.cliets.values():

s.close()

self.socket.close()if __name__ == '__main__':

cs= ChatTcpServer('127.0.0.1',9999)

cs.start()#print('3~~~~~~~~~~~~~~~~~~~',threading.enumerate())

#cs.stop()

problem:there has a error when cliens exit

ConnectionAbortedError

importsocketimportthreadingclassChatTcpServer:def __init__(self,ip,port):

self.ip=ip

self.port=port

self.cliets={}#实例化就创建一个socket对象

self.socket =socket.socket()

self.event=threading.Event()defstart(self):

self.socket.bind((self.ip,self.port))

self.socket.listen()

threading.Thread(target=self._accept,name="_aceept").start()def _accept(self): #只开启一个accept线程,连接产生的new_socket负责和线程receive同信

while notself.event.is_set():

new_socket,raddr= self.socket.accept() #阻塞主线程,所以开启一个工作线程receive

threading.Thread(target=self._receive,name="reveive",args=(new_socket,)).start()

self.cliets[new_socket]=raddrprint(self.cliets)print(type(self.cliets.keys()))def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程

while notself.event.is_set():

data= new_socket.recv(1024) #阻塞

for k inself.cliets.keys():

k.send('ack {}'.format(data).encode())defstop(self):ifself.cliets:for s inself.cliets.values():

s.close()

self.socket.close()

self.event.set()if __name__ == '__main__':

cs= ChatTcpServer('127.0.0.1',9999)

cs.start()whileTrue:

cmd= input("please set stop:>>>")if cmd == 'quit':

cs.stop()break

以上版本服务端可以断开连接,但是客户端断开连接抛出异常

增加客户端断开命令

客户端主动断开连接的问题,服务端知道自己何时断开

如果是客户端断开服务器不知道,所有好的做法客户端发出特殊消息通知服务器断开连接,但是客户端主动断开服务端主动发送一个空消息,超时返回异常,捕获异常并清理连接,即使为客户端提供了断开命令,也不能保证客户端会使用它断开连接,还是要增加这个退出功能

def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程

while notself.event.is_set():

data= new_socket.recv(1024) #阻塞

if data == b"quit":

self.cliets.pop(new_socket)

new_socket.close()break

for k inself.cliets.keys():

k.send('ack {}'.format(data).encode())

socket常用方法

socket = socket.socket()

socket.recv(1024) bufsize=1024 获取数据,默认是阻塞状态

socket.recvfrom(1024) 获取数据,返回一个二元组(bytes,address)

socket.recv_into(buffer=1024,nbytes=10,flags=None) 获取到nbytes的数据后,存储到buffer中,如果nbytes没有指定或者0,将buffer大小的数据存入buffer中,返回接收的字节数

socket.send(bytes) tcp发送设备

socket.sendall(bytes) tcp发送全部设备,成功返回None

Makefile

socket.socket().makefile(mode='r',buffering=None) 创建一个与该套接字相关联的文件对象,将recv方法看作读方法,将send方法看作写方法

socket.getpeername() 返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)

sockete.getsockname() 返回套接字自己的地址,通常是一个元祖(ipaddr,port)

socket.setbloking(flag) 如果flag为0则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)

非阻塞模式下,如果调用recv没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常

socket.settimeout(value) 设置套接字操作的超时期,timeout是一个浮点数单位秒

值为none表示没有超时期,一般超时期应该在刚创建套接字时设置,因为他们可能用于连接的操作(connect())

read和readline(行读取,包括换行符)

importsocket

socket=socket.socket()

socket.bind(('127.0.0.1',9999))

socket.listen()whileTrue:

new_socket,raddr=socket.accept()

f= new_socket.makefile('rw')print(f)

line= f.readline() #Read and return one line from the stream

line = f.read(10) #Read up to n bytes from the object and return them

#只有输入十个字节才会return

print(line)

f.write('ack {}'.format(line))

f.flush()

f.close()

client编写

importsocket

socket=socket.socket()

socket.bind(('127.0.0.1',9999)) #server ip

socket.listen()

new_socket,raddr=socket.accept()

data= new_socket.recv(1024)print(data)

new_socket.send('ack {}'.format(data).encode())

importsocketimportthreadingimportdatetimeimportlogging

FORMAT= '%(asctime)s %(threadName)s %(thread)d %(message)s'logging.basicConfig(level=logging.INFO,format=FORMAT)classChatClient:def __init__(self,ip='127.0.0.1',port=9999):

self.ip=ip

self.port=port

self.sock=socket.socket()

self.event=threading.Event()defstart(self):

self.sock.connect((self.ip,self.port))

self.send('i am ready')

threading.Thread(target=self.receive,name='receive').start()defreceive(self):while notself.event.is_set():try: #连接不成功,捕获异常

data = self.sock.recv(1024)

logging.info(data)exceptException as e:

logging.info(e)defsend(self,msg:str):

self.sock.send('{}'.format(msg).encode())defstop(self):

self.sock.close()

self.event.set()

logging.info('Client stops')defmain():

cc=ChatClient()

cc.start()whileTrue:

cmd= input("please set a number:")if cmd.strip() == b'quit':

cc.stop()breakcc.send(cmd)if __name__ == '__main__':

main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值