python3网络编程 —— 用多线程实现最简单的聊天工具

本文转载自:http://blog.sina.com.cn/s/blog_d4881fec0102xc0j.html


socket通讯必须有服务端和客户端

 

创建服务端:

 

【第一步】:先创建一个socket类型的对象s

s=socket.socket(familly,type)

        family参数可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(用于IPV4协议的TCP UDP)。

        type参数一般为SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),很少用SOCK_RAWraw套接字)。可以简单的认为:

SOCK_STREAM :能确保数据达到,用于发送文件数据。

SOCK_DGRAM  :不能确保数据到达,用于局域网广播消息。

SOCK_RAW        :需要自定义IP包,暂不解释。

其实后面还有参数proto用来指明要接收的协议包?fileno参数大概是内存地址一类的东西?默认都不填。

 

【第二步】:调用socket对象里的bind方法绑定IP和端口:

s.bind((host,port))

        bind只有一个tuple(元组)类型的参数,host为客户端的ip0.0.0.0表示任何ip,本地测试也可以用127.0.0.1,端口最好大于1024

 

【第三步】:设置监听数:

s.listen( )

参数填最大监听的连接数。

 

【第四步】:accept方法接收客户端的连接:

connect ,address = s.accept( )

        无参数,程序进入阻塞模式直到有客户端连接,接收到连接后会返回一个元组形式的参数:connect为新产生的socket对象,address为客户端的ip

 

【第五步】:收发数据及关闭连接:

必须使accept返回的新socket对象connect来收发数据,connect里的sendrecv方法

connect.send("string ".encode('utf8'))

connect.recv(size).decode('utf8')

注:send方法在Python2里参数是字符串,在Python3里参数是二进制对象,所以必须先用encode('utf8')将字符串重新编码

recv方法参数为读取的缓冲区大小size,与send方法同理,接收到数据后必须用decode('utf8')将数据解码成可读的字符串

最后会话结束s.close()关闭连接

 

 

创建客户端:

 

【第一步】:先创建一个socket类型的对象s

s=socket.socket(familly,type)

与服务端同理

 

【第二步】:连接服务端:

s.connect((host,port))

host为服务端主机的ip,端口为服务端定义的端口。

 

【第三步】:收发数据及关闭连接:

与服务端同理的sendrecv方法

s.send()s.recv()s.close()


体代码(必须在CMD里运行,每次服务端或客户端仅能发送一条信息,if内代码可精简):

服务端:

import socket  
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.bind(("127.0.0.1",1234))  
s.listen(2)  
sock,addr=s.accept()  
while True:  
    t=sock.recv(1024).decode('utf8')   #服务端先接收信息  
    if t == "exit":  
        break  
    print(t)  
    t=input()  
    if t == "exit":  
        break  
    sock.send(t.encode('utf8'))  
s.close()  

客户端:
import socket  
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.connect(("127.0.0.1",1234))  
while True:  
    t=input()  
    s.send(t.encode('utf8'))   #客户端先发送信息  
    if t == "exit":  
        break  
    t=s.recv(1024).decode("utf8")  
    if t == "exit":  
        break  
    print(t)  
s.close()  



多线程改进:

        由于input函数的阻塞作用,以上的代码发完一条信息,只能等待另一端的信息发过来才能继续发送。 这时就要考虑将输入与接收分开来,将接收的函数(或方法)从主线程里抓出来丢到另一个线程里单独运行,为实现这一功能,必须引入多线程。

        多线程的使用别人的教程写得都太杂乱,什么select都来了……,其实很简单,Python里两句话搞定:


import  threading   #引入多线程模块

trd=threading.Thread(target=rec,args=(sock,))    #创建多线程

trd.start()               #启动多线程


       注:target参数为需要跑起来的函数名,仅函数名,不需要括号,args为传递到target函数里的参数(元组类型),这里仅传入收发数据用的socket对象即可

 

改良后的代码(须在CMD里运行):

服务端:

import socket  
import threading  
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.bind(("127.0.0.1",9999))  
s.listen(2)  
sock,addr=s.accept()  
true=True  
def rec(sock):  
    global true  
    while true:  
        t=sock.recv(1024).decode('utf8')  #函数的核心语句就一条接收方法  
        if t == "exit":  
            true=False  
        print(t)  
trd=threading.Thread(target=rec,args=(sock,))  
trd.start()  
while true:  
    t=input()  
    sock.send(t.encode('utf8'))  
    if t == "exit":  
        true=False  
s.close() 

客户端:

import socket  
import threading  
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.connect(("127.0.0.1",9999))  
true=True  
def rec(s):  
    global true  
    while true:  
        t=s.recv(1024).decode("utf8")  #客户端也同理  
        if t == "exit":  
            true=False  
        print(t)  
trd=threading.Thread(target=rec,args=(s,))  
trd.start()  
while true:  
    t=input()  
    s.send(t.encode('utf8'))  
    if t == "exit":  
        true=False  
s.close()  

最后,在cmd中分别用python执行客户端和服务器两个文件,就能实现客户端和服务器的通信了!快去试试吧!

猜你喜欢

转载自blog.csdn.net/bobyuan888/article/details/79923219