手把手教你实现python网络聊天程序(可一人连续发送多句话)
- 1. socket的使用
- 1.1 socket的创建:
- 1.2 socket类的常用方法
- 1.3 socket入门实战
- 1.3.1 TCP聊天程序(一人一句)的实现思想
- 1.3.2 TCP聊天程序(一人一句)的实现代码
- 2.改进我们的程序
- 2.1改进后的思想
- 2.2 threading模块的使用
- 2.2.1 多线程的创建
- 2.2.2thread的参数介绍
- 2.2.3 threading的使用
- 2.3tkinter模块的使用
- 2.4最终代码
1. socket的使用
1.1 socket的创建:
s=socket.socket(AddressFamily,Type)
AddressFamily的可选参数:
可选参数 | 介绍 |
AF_INET | 用于Internet进程间通讯 |
AF_UNIX | 用于进程间通讯 |
Type的可选参数:
可选参数 | 介绍 |
SOCK_STREAM | 流式套接字,主要用于TCP协议 |
SOCK_DGRAM | 数据报套接字,主要用于UDP协议 |
1.2 socket类的常用方法
常用方法 | 介绍 |
s.bind((host,port)) | 绑定地址(host,port)到套接字 |
s.listen() | 开始TCP监听,可选参数为操作系统可挂起的最大连接数量,至少为1 |
s.accept() | 被动接收TCP客户端的连接,用阻塞的方式等待连接到来 |
s.connect(address) | 主动初始化TCP服务链接,address格式的元组(hostname,port)若连接出错,则返回socket.error |
s.recv(bufsize) | 接收TCP数据,以字符串形式返回。bufsize指定接收的最大数量 |
s.send() | 发送TCP数据,将string中数据发送到连接的套接字,返回值小于等于发送字节数 |
s.sendall() | 完整发送TCP数据,成功返回none,失败抛出异常 |
s.recvfrom() | 接收UDP数据,返回值为(data,address),data为包含数据的字符串,address为发送数据的地址 |
s.sendto() | 发送UDP数据,将数据发送到套接字。(ipaddr,port)元组,指定远程地址。返回发送字节数 |
s.close() | 关闭套接字 |
1.3 socket入门实战
1.3.1 TCP聊天程序(一人一句)的实现思想
1.3.2 TCP聊天程序(一人一句)的实现代码
服务器代码:
import socket
host=’127.0.0.1’
port=996
print('服务器IP:'+host+'\n')
print('服务器端口号:'+str(port)+'\n')
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建套接字
s.bind((host,port))#绑定ip和port
s.listen(10)#设置最大监听量
sock,addr=s.accept()
print('连接已经建立')
info=sock.recv(1024).decode()
while True:
if info:
print('接收到的内容:'+info)
send_data=input('输入发送内容:')
sock.send(send_data.encode())
info=sock.recv(1024).decode()
sock.close()
s.close()
客户端代码:
import socket
s=socket.socket()
host=’127.0.0.1’
port=996
s.connect((host,port))#连接服务器
print('已连接')
info=''
while True:
send_data=input('输入发送内容:')
s.send(send_data.encode())
info=s.recv(1024).decode()
print('接收的内容:'+info)
s.close()
实现效果:
2.改进我们的程序
现在,我们已经有了一人一句的聊天程序的铺垫,我们可以进一步实现一人可以多句的聊天程序。我们在实现的时候需要使用以下一些模块:tkinter和threading。主要思想为:每台电脑同时作为服务器和客户端,服务器只负责循环接收消息 ,而客户端只负责发送消息。
2.1改进后的思想
2.2 threading模块的使用
2.2.1 多线程的创建
thread ([group[,target[,name[,args[,kwarges]]]]])
2.2.2thread的参数介绍
参数 | 介绍 |
group | 值为none |
target | 表示一个可调用对象 |
name | 当前线程名称 |
args | 传递给target函数的一个参数元组 |
kwargs | 传递给target函数的一个参数字典 |
2.2.3 threading的使用
我们在这个程序中只需要创建threading.thread的子类即可,示例:
import threading
class SubThread(threading.Thread):
def run(self):
pass#重写run方法
if __name__ == '__main__':
p1 = SubThread()
p1.start()
2.3tkinter模块的使用
我们在这个程序中需要使用一个按钮(Button),一个列表框(Listbox)和一个输入框(Entry),示例:
from tkinter import *
root = Tk()
v = StringVar()
thebutton = Button(root, text="send", command=send)
thebutton.grid(row=11, column=5)
thelist = Listbox(root)
thelist.grid(row=0, column=1, rowspan=10, columnspan=5)
thelist.insert(END, '1st tk')
theentry = Entry(root, textvariable=v)
theentry.grid(row=11, column=1, columnspan=4)
mainloop()
2.4最终代码
first.py
import socket
import threading
from tkinter import *
class SubThread(threading.Thread):
def run(self):
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('127.0.0.1', 996))
while True:
s1.listen(10)
sock, addr = s1.accept()
info = sock.recv(1024).decode()
global thelist
thelist.insert(END, 'ta:' + info)
def send():
s2 = socket.socket()
s2.connect(('127.0.0.1', 669))
global v
s2.send(v.get().encode())
global thelist
thelist.insert(END, 'me:' + v.get())
v.set('')
if __name__ == '__main__':
root = Tk()
v = StringVar()
thebutton = Button(root, text="send", command=send)
thebutton.grid(row=11, column=5)
thelist = Listbox(root)
thelist.grid(row=0, column=1, rowspan=10, columnspan=5)
thelist.insert(END, '1st tk')
theentry = Entry(root, textvariable=v)
theentry.grid(row=11, column=1, columnspan=4)
p1 = SubThread()
p1.start()
mainloop()
second.py
import socket
import threading
from tkinter import *
class SubThread(threading.Thread):
def run(self):
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('127.0.0.1', 669))
while True:
s1.listen(10)
sock, addr = s1.accept()
info = sock.recv(1024).decode()
global thelist
thelist.insert(END, 'ta:' + info)
def send():
s2 = socket.socket()
s2.connect(('127.0.0.1', 996))
global v
s2.send(v.get().encode())
global thelist
thelist.insert(END, 'me:' + v.get())
v.set('')
if __name__ == '__main__':
root = Tk()
v = StringVar()
thebutton = Button(root, text="send", command=send)
thebutton.grid(row=11, column=5)
thelist = Listbox(root)
thelist.grid(row=0, column=1, rowspan=10, columnspan=5)
thelist.insert(END, '2nd tk')
theentry = Entry(root, textvariable=v)
theentry.grid(row=11, column=1, columnspan=4)
p1 = SubThread()
p1.start()
mainloop()