共计 7845 个字符,预计需要花费 20 分钟才能阅读完成。
一、客户端与服务端通信流程
二、客户端与服务端通信代码
服务端 (server.py)
import socket
# 1、创建 socket
# 参数 1:选择使用 ip 类型,AF_INET 代表 ipv4,AF_INET6 表示 ipv6
# 参数 2:选择协议,SOCK_STREAM 表示 TCP 协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2、绑定
# 参数是一个元组,元组的第一个元素为服务器本机 IP,第二个元素为端口号,建议使用 8000(8000 以下的好多都是被其他程序所占用)以上的端口,最大使用到 65535
server.bind(("10.0.128.226", 8000))
# 3、监听:设置最大连接数
server.listen(40)
# 4、
while 1:
print("等待客户端连接……")
# 两个返回值,第一个返回值为连接的客户端的唯一标识,第二个返回值为客户端的 ip 地址
clientSocket, clientAddr = server.accept()
print("连接成功……")
print(clientSocket)
print(clientAddr)
# 接收数据
data = clientSocket.recv(1024)
print("%s 说:%s"%(clientAddr[0], data.decode("utf-8")))
# 响应数据
clientSocket.send("You are right!".encode("utf-8"))
客户端 (client.py)
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 参数是一个元组,元组的第一个元素为服务器所在机器的 IP,第二个元素为端口号,为要连接的服务器开放的端口
client.connect(("10.0.128.226", 8000))
# 发送数据
client.send("zutuanxue_com is a good man".encode("utf-8"))
data = client.recv(1024)
print("服务器说:%s"%(data.decode("utf-8")))
三、基于 TCP 实现聊天软件
-
服务器
main.py
from server import Server from db import Db def main(): Db() server = Server(4, "TCP", "192.168.1.31", 8081, 10) server.start() if __name__ == "__main__": main()
server.py
import socket from interaction_thread import InteractionThread def single(cls): instance = {} def inner(*args, **kwargs): if cls not in instance: instance[cls] = cls(*args, **kwargs) return instance[cls] return inner @single class Server(object): def __init__(self, ip4or6, protocol, ip, port, num): if ip4or6 == 4: self.ip4or6 = socket.AF_INET else: self.ip4or6 = socket.AF_INET6 if protocol.upper() == "TCP": self.protocol = socket.SOCK_STREAM else: self.protocol = socket.SOCK_DGRAM self.socket = None self.ip = ip self.port = port self.num = num def start(self): self.socket = socket.socket(self.ip4or6, self.protocol) self.socket.bind((self.ip, self.port)) self.socket.listen(self.num) while True: clientSocket, clientAddr = self.socket.accept() print("用户 %s 连接成功" % (clientAddr[0])) # 为每个用户开启一个线程,和用户进行交互 InteractionThread(clientSocket, clientAddr).start()
user.py
class User(object): def __init__(self, account, passwd, name, clientSocket=None): self.account = account self.passwd = passwd self.name = name self.clientSocket = clientSocket self.friendsDict = {} # account:user self.friendsFlag = {} # account:1/0
db.py
def single(cls): instance = {} def inner(*args, **kwargs): if cls not in instance: instance[cls] = cls(*args, **kwargs) return instance[cls] return inner @single class Db(object): def __init__(self): self.users = {} # account:user
interaction_thread.py
import threading from db import Db from user import User class InteractionThread(threading.Thread): def __init__(self, clientSocket, clientAddr): super().__init__() self.clientSocket = clientSocket self.clientAddr = clientAddr self.myself = None def run(self): db = Db() while True: data = self.clientSocket.recv(1024).decode("utf-8") print("服务器收到 %s 的 %s 信息"%(self.clientAddr[0], data)) dataArr = data.split("#") flag = dataArr[0] if flag == "register": if len(dataArr) != 4: self.clientSocket.send("注册时输入有误".encode("utf-8")) continue account = dataArr[1] user = db.users.get(account) if user: self.clientSocket.send("账号存在,注册失败".encode("utf-8")) else: user = User(account, dataArr[2], dataArr[3]) db.users[account] = user self.clientSocket.send("注册成功".encode("utf-8")) elif flag == "login": if len(dataArr) != 3: self.clientSocket.send("登陆时输入有误".encode("utf-8")) continue account = dataArr[1] user = db.users.get(account) if user: if user.passwd == dataArr[2]: # 给账号的 clientSocket 属性赋值 user.clientSocket = self.clientSocket self.clientSocket.send("登陆成功".encode("utf-8")) self.myself = user else: self.clientSocket.send("密码错误,登陆失败".encode("utf-8")) else: self.clientSocket.send("账号不存在,登陆失败".encode("utf-8")) elif flag == "talk": if len(dataArr) != 2: self.clientSocket.send("群聊时输入有误".encode("utf-8")) continue # 自己未登录 if not self.myself: self.clientSocket.send("未登录,请登录后操作".encode("utf-8")) continue for account in db.users: user = db.users.get(account) if (not user.clientSocket) or account == self.myself.account: continue # xxx 说 (群聊):xxxxxxxxxx info = "%s[%s] 说 (群聊):%s" % (self.myself.name, self.myself.account, dataArr[1]) user.clientSocket.send(info.encode("utf-8")) elif flag == "quite": if len(dataArr) != 2: self.clientSocket.send("退出时输入有误".encode("utf-8")) continue account = dataArr[1] if account == self.myself.account: db.users.get(account).clientSocket = None self.myself = None self.clientSocket.send("成功退出".encode("utf-8")) else: self.clientSocket.send("只能退出自己的账号,退出失败".encode("utf-8")) elif flag == "add": if len(dataArr) != 2: self.clientSocket.send("添加好友时输入有误".encode("utf-8")) continue account = dataArr[1] user = db.users.get(account) if user: friend = self.myself.friendsDict.get(account) if friend: self.clientSocket.send("该用户已是好友".encode("utf-8")) else: # 对方成为我的好友 self.myself.friendsDict[account] = user self.myself.friendsFlag[account] = 1 self.clientSocket.send("好友添加成功".encode("utf-8")) # 把我添加到对方的好友列表 user.friendsDict[self.myself.account] = self.myself # 但是对方未验证 user.friendsFlag[self.myself.account] = 0 # 告诉对方 info = "%s[%s] 添加你为好友" % (self.myself.name, self.myself.account) user.clientSocket.send(info.encode("utf-8")) else: self.clientSocket.send("账号不存在,添加好友失败".encode("utf-8")) elif flag == "check": if len(dataArr) != 3: self.clientSocket.send("验证好友时输入有误".encode("utf-8")) continue friendAccount = dataArr[1] friend = self.myself.friendsDict.get(friendAccount) flag = dataArr[2] if flag == "yes": self.myself.friendsFlag[friendAccount] = 1 # 告诉对方 info = "%s[%s] 已同意添加好友请求"%(self.myself.name, self.myself.account) friend.clientSocket.send(info.encode("utf-8")) elif flag == "no": friend.friendsDict.pop(self.myself.account) friend.friendsFlag.pop(self.myself.account) self.myself.friendsDict.pop(friendAccount) self.myself.friendsFlag.pop(friendAccount) info = "%s[%s] 已拒绝添加好友请求" % (self.myself.name, self.myself.account) friend.clientSocket.send(info.encode("utf-8")) elif flag == "say": if len(dataArr) != 3: self.clientSocket.send("私聊时输入有误".encode("utf-8")) continue account = dataArr[1] friend = db.users.get(account) # 验证对方是否添加你为好友 if friend.friendsFlag[self.myself.account] == 1: info = "%s[%s] 说 (私聊):%s" % (self.myself.name, self.myself.account, dataArr[2]) friend.clientSocket.send(info.encode("utf-8")) else: self.clientSocket.send("对方未添加你为好友".encode("utf-8")) elif flag == "del": if len(dataArr) != 2: self.clientSocket.send("删除好友时输入有误".encode("utf-8")) continue account = dataArr[1] friend = db.users.get(account) friend.friendsDict.pop(self.myself.account) friend.friendsFlag.pop(self.myself.account) self.myself.friendsDict.pop(account) self.myself.friendsFlag.pop(account) info = "%s[%s] 将你删除好友"%(self.myself.name, self.myself.account) friend.clientSocket.send(info.encode("utf-8"))
-
客户端
main.py
from client import Client from send_thread import SendThread
from recv_thread import RecvThread
def main():
c = Client(4,“TCP”,“192.168.1.31”, 8081)
c.start()
# 启动发送线程
sth = SendThread(c)
sth.start()
# 启动接收线程
rth = RecvThread(c)
rth.start()
# 等待发送与接收线程的结束
sth.join()
rth.join()
if name ==“main”:
main()
client.py
```python
import socket
def single(cls):
instance = {}
def inner(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return inner
@single
class Client(object):
def __init__(self, ip4or6, protocol, ip, port):
if ip4or6 == 4:
self.ip4or6 = socket.AF_INET
else:
self.ip4or6 = socket.AF_INET6
if protocol.upper() == "TCP":
self.protocol = socket.SOCK_STREAM
else:
self.protocol = socket.SOCK_DGRAM
self.socket = None
self.ip = ip
self.port = port
def start(self):
self.socket = socket.socket(self.ip4or6, self.protocol)
self.socket.connect((self.ip, self.port))
send_thread.py
import threading
class SendThread(threading.Thread):
def __init__(self, client):
super().__init__()
self.client = client
def run(self):
while True:
# 注册 register#account#passwd#name
# 登陆 login#account#passwd
# 群聊 talk#data
# 退出登录 quite#account
# 添加好友 add#account
# 验证好友添加 check#account#yes/no
# 与好友私聊 say#account#data
# 删除好友 del#account
# register#a#1#zutuanxue_com
# register#b#2#kaige
# register#c#3#kaishen
# talk#zutuanxue_com is a good man
# login#a#1
# login#b#2
# login#c#3
# quite#c
# add#b check#a#yes
# add#c check#b#no
# say#b#zutuanxue_com is a good man
# say#a#zutuanxue_com is a good man
# say#c#zutuanxue_com is a good man
# del#b
data = input()
self.client.socket.send(data.encode("utf-8"))
recv_thread.py
import threading
class RecvThread(threading.Thread):
def __init__(self, client):
super().__init__()
self.client = client
def run(self):
while True:
print(self.client.socket.recv(1024).decode("utf-8"))
正文完
星哥玩云-微信公众号