一、HTTP协议的socket通信

1、server.py

# 服务端
import sys
import socket ip_point = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_point)
sk.listen(5)
print("进入监听状态...")
conn,addr = sk.accept()
print(addr)
client_data = conn.recv(1024)
print(client_data.decode("utf-8"))
conn.send("服务端回复内容:我很好。".encode("utf-8"))
conn.close()

2、client.py

# 客户端
import socket
ip_port = ("127.0.0.1",9999)
sk = socket.socket()
sk.connect(ip_port)
sk.send("客户端发送数据:你好吗?".encode("utf-8"))
server_replay = sk.recv(1024)
print("get data:",server_replay.decode("utf-8"))
sk.close()

3、执行结果

4、流程说明

  1. 建立socket对象
  2. socket绑定ip和端口
  3. listen
  4. 有连接,accept
  5. 读写数据
  6. 关闭

二、UDP协议的socket通信

1、server.py

# 服务端
from socket import *
from time import ctime HOST = ''
PORT = 1200
BUFSIZ = 128
ADDR = (HOST, PORT) # 创建一个服务器端UDP套接字
udpServer = socket(AF_INET, SOCK_DGRAM)
# 绑定服务器套接字
udpServer.bind(ADDR)
print('已经进入监听状态...')
# 接收来自客户端的数据
data, addr = udpServer.recvfrom(BUFSIZ)
print(u"得到客户端数据:",data.decode("utf-8"))
# 向客户端发送数据
udpServer.sendto(b'%s %s[%s]' % ("服务器发送消息:".encode("utf-8"),ctime().encode("utf-8"),data),addr)
print('向客户端发送数据:', data)
udpServer.close()

2、client.py

# 客户端
#encoding=utf-8
from socket import * HOST = 'localhost'
PORT = 1200
BUFSIZ = 128
ADDR = (HOST, PORT) # 创建客户端UDP套接字
udpClient = socket(AF_INET, SOCK_DGRAM)
data = input('>')
# 向服务器端发送数据
udpClient.sendto(data.encode("utf-8"), ADDR)
# 接收来自服务器端的数据
data, ADDR = udpClient.recvfrom(BUFSIZ)
print(data.decode("utf-8"))
udpClient.close()

3、结果

三、实现一个调用系统命令的例子

1、server.py

import os
if __name__ == '__main__':
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8001))
sock.listen(5)
while True:
connection,address = sock.accept()
try:
connection.settimeout(5)
command = connection.recv(1024)
print(command)
result=os.popen(command.decode("utf-8")) #拿到执行后管道命令后的结果
connection.send(command)
connection.send(result.read().encode("utf-8"))
except socket.timeout:
print('time out')
connection.close()

2、client.py

if __name__ == '__main__':
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 8001))
import time
time.sleep(2)
sock.send('ipconfig'.encode("utf-8"))
print("command:",sock.recv(10).decode("utf-8"))
print ("command result:",sock.recv(1024).decode("utf-8"))
sock.close()

3、执行结果

客户端向服务端发送一个dos命令
服务服务端返回命令响应结果

四、实现聊天室

1、实现的效果:

2、服务器端代码

# encoding=utf-8
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver # 事件处理器
from twisted.internet import reactor class Chat(LineReceiver):#本质就是一个Protocol类的子类,真正管理server端和每个客户端通讯逻辑的,每一个客户端的连接,都会自动生成一个Chat类的实例。
message_dict={} #类变量,存储所有用户发送的消息,key:收消息的用户名,value:列表存所有发送来的消息
def __init__(self, users):
self.users = users #把ChatFactory类中的实例变量user字典,用self.users 变量引用这个字典
self.name = None #当前连接的用户名,你起的名字会存到这个变量里面
self.state = "GETNAME" #状态位,确认当前连接的客户端起名名字没有,没起名状态是GETNAME,起了名状态是CHAT def connectionMade(self): # 连接开始,且开始做处理
if self.name is None: #判断客户端有没有名字
self.sendLine(u"你叫什么名字?".encode("utf-8")) #给客户端发送指定消息! def connectionLost(self, reason): #连接断开的时候做什么处理
print("断开时的用户名:",self.name)
if self.name in self.users:
del self.users[self.name] #user字典是一个全局变量,value存的是连接对象本身(chat的实例),已经断开不是连接状态了,删除掉。
try:
if self.name in Chat.message_dict: #把别人给你发的消息,从消息字典中删除掉
del Chat.message_dict[self.name]
except:
print("删除用户的聊天记录失败") def lineReceived(self, line): # 收到客户端发来的消息做什么处理,会自动调用
#客户端发送的消息,会自动传到line这个变量里面
if self.state == "GETNAME": # 根据状态开始选择不同得内容处理
print("line:",line)
self.handle_GETNAME(line.decode("utf-8")) #调用起名字的处理方法handle_GETNAME
else:
self.handle_CHAT(line.decode("utf-8")) #调用聊天的处理方法handle_CHAT def handle_GETNAME(self, name): #处理用户起名字的逻辑
if name in self.users:
self.sendLine(u"名字冲突了,请做另外起个用户名.\n".encode("utf-8") ) # 每个用户只能有一个聊天通信存在
return
self.sendLine(("欢迎, %s!\n" %name).encode("utf-8")) #给客户端发送一个消息,告诉你欢迎xxx
self.name = name #用户发来的名字,赋值给self.name变量,连接的客户端的名字
self.users[name] = self #把self,自己,放到users字典中(存所有用户的连接对象---Chat的实例--self)
self.state = "CHAT" #把用户从GETNAME状态改为CHAT状态 def handle_CHAT(self, message): # 处理用户聊天的逻辑
#客户端输入:zhangsan:你吃了吗?
if "getmessage" in message: #发的命令是getmessage,读别人给你发的消息,取消息的用户名:getmessage
username = message.split(":")[0]#取到需要取消息的用户名
print("*"*2,username,Chat.message_dict)
#判断取消息的用户名在不在消息字典中,或者是不是消息为空
if (username not in Chat.message_dict) or Chat.message_dict[username] == []:
self.users[username].sendLine("没有别人给你发送的数据".encode("utf-8"))
print(message,"---->","没有别人给你发送的数据","\n")
return
message_list=Chat.message_dict[username]#把消息的列表取出来
print(message_list)
if username in self.users:#把所有的链接对象遍历一遍
print(username,self.users[username])
#self.users[username]--》username对应的链接对象取出来,然后把列表以字符串的形式发给客户端
#客户端,需要用eval(列表的字符串)---》转换为一个列表
#用这个连接对象发给用户这个列表字符串
self.users[username].sendLine(("%s" % message_list).encode("utf-8"))
del Chat.message_dict[username]#删除刚才收走的消息
return elif ":" in message:
'''
          消息格式:
huqiqi:zhangsan:你吃了么?
'''
if message.count(":")!=2:
self.sendLine("您发送的消息格式不对,请输入send命令后,按照格式‘用户名:消息’来进行聊天信息发送。".encode("utf8"))
print("您发送的消息格式不对,请输入send命令后,按照格式‘用户名:消息’来进行聊天信息发送。")
return
from_username = message.split(":")[0]
to_username = message.split(":")[1]
chat_message = message.split(":")[2]
if to_username not in Chat.message_dict:#判断接受者是否在消息字典中,不在,声明一个空列表作为value
Chat.message_dict[to_username] = []
Chat.message_dict[to_username].append((from_username,chat_message))#向列表中追加这个消息:(发消息人名字,消息体)
print(message, "---->", "增加了用户%s发送的消息:%s" %(to_username,(from_username,chat_message)) , "\n")
return #查看哪些用户处于登录状态
elif message.strip() =="list": #查看哪些用户是处于登录状态
print("list response")
self.sendLine((str([username for username in self.users]) + "\n").encode("utf-8"))
print(message, "---->", (str([username for username in self.users]) + "\n"),"\n")
return
#如果没有识别用户命令,提示用户可以输入使用的命令
else: #非上面的消息,就返回命令提示语
send_message= ("""请指定用户名,输入send后,按照格式‘用户名:消息’来进行聊天信息发送。
\n或者输入list查看当前登录用户\n输入getmessage获取其他用户发给你的聊天信息\n""")
#print (type(send_message))
self.sendLine(send_message.encode("utf-8"))
print(message, "---->",send_message,"\n")
return class ChatFactory(Factory): #实现的工厂类,必须定义buildProtocol方法,必须返回一个Protocol子类的实例对象
def __init__(self):
self.users = {} #将所有与服务器端连接的对象存放到此字典中,所有的实例均可以使用此字典获取所有的连接对象,字典来存储所有的连接,key:和server连接的客户端名字(第一次连接的时候取的);value:连接对象也就是Chat的实例 def buildProtocol(self, addr):
return Chat(self.users) #每次一个新的客户端建立了连接,那么会自动生成Chat类的实例,这个实例负责管理服务端和客户端的所有通讯细节,会根据网络事件,触发不同内置的事件方法! if __name__ == '__main__':
reactor.listenTCP(1200, ChatFactory()) #监听端口,指定通信协议的工厂类实例
print ("开始进入监听状态...")
reactor.run() #开始监听

3、客户端代码

# socket client end
from socket import *
import time
s = socket(AF_INET, SOCK_STREAM)
remote_host = gethostname()print ('remote_host:', remote_host)
port = 1200
s.connect((remote_host, port)) # 发起连接
print (u"连接从", s.getsockname()) # 返回套接字自己的地址。通常是一个元组(ipaddr,port)
print (u"连接到", s.getpeername()) # 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port) print (u'从服务器返回消息:')
print (s.recv(1200).decode("utf-8").strip()) while 1:
username = input("请输入你要使用的英文用户名:\n")
s.send(('%s\r\n' %username.strip()).encode("utf-8")) # 发送一行字符串(以\r\n 结束)到服务器端
print (u'从服务器返回消息:')
response = s.recv(1200).decode("utf-8").strip()
print (response)
if "冲突" not in response:
break print("*"*50)
print("""查看当前登录用户列表的命令:list
查看别人给你发送的消息命令要求:getmessage
给别人发送消息,请先输入send,然后按照如下格式发送聊天信息:
username:要发送的消息
断开连接请输入bye""")
print("*"*50) while 1:
send_message=input("请输入发送的信息:\n")
if send_message=="getmessage" :
#当前用户名:getmessage --->发给服务器
s.send(('%s:%s\r\n' %(username,send_message)).encode("utf-8"))
print (u'从服务器返回消息:')
content = s.recv(1200).decode("utf-8").strip()
#返回的消息内容是个列表[(发消息人名1,消息1),(发消息人名2,消息2),(发消息人名3,消息3)....]
try:
if "[" in content and ']' in content:
#服务器返回的是个字符串,用eval转换为列表对象
info_list = eval(content)
for index,info in enumerate(info_list):#遍历
#index是序号,info[0]发消息的人名,info[1]是发送的消息体
print("%s>用户%s信息:%s" %(index,info[0],info[1]))
else:
print(content)
except:
print("从服务器收到的数据是无效数据!数据为%s" %content)
elif send_message=="list":
s.send(('%s\r\n' %send_message).encode("utf-8"))
print (u'从服务器返回消息:')
print (s.recv(1200).decode("utf-8").strip())
elif send_message=="bye":
s.close()
break
elif send_message=="send":
print("请输入你要给用户发送的消息,消息格式:\n用户名:您要发的消息内容\n")
info = input(">")
s.send(('%s:%s\r\n' %(username,info.strip())).encode("utf-8"))#发给server端
print("发送的消息:",('%s:%s\r\n' %(username,info.strip()))) #打印发送的消息
else:
print("输入的消息无效:请使用getmessage、list、bye或者send之一")
time.sleep(1)
continue

Socket编程和实现聊天室的更多相关文章

  1. Java 多线程Socket编程通讯--实现聊天室代码

    1.创建服务器类 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import ja ...

  2. 网络编程TCP协议-聊天室

    网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...

  3. 示例:Socket应用之简易聊天室

    在实际应用中,Server总是在指定的端口上监听是否有Client请求,一旦监听到Client请求,Server就会启动一个线程来响应该请求,而Server本身在启动完线程之后马上又进入监听状态. 示 ...

  4. Express+Socket.IO 实现简易聊天室

    代码地址如下:http://www.demodashi.com/demo/12477.html 闲暇之余研究了一下 Socket.io,搭建了一个简易版的聊天室,如有不对之处还望指正,先上效果图: 首 ...

  5. C#编程 socket编程之unity聊天室

    上面我们创建了tcp的客户端和服务端,但是只能进行消息的一次收发.这次我们做一个unity的简易聊天室,使用了线程,可以使用多个客户端连接服务器,并且一个客户端给服务器发消息后,服务器会将消息群发给所 ...

  6. 使用socket.io打造公共聊天室

    最近的计算机网络课上老师开始讲socket,tcp相关的知识,当时脑袋里就蹦出一个想法,那就是打造一个聊天室.实现方式也挺多的,常见的可以用C++或者Java进行socket编程来构建这么一个聊天室. ...

  7. 使用Android网络编程实现简易聊天室

    在Java中我们可以利用socket编程实现聊天室,在Android中也一样,因为Android完全支持JDK本身的TCP.UDP网络通信API.我们可以使用ServerSocket.Socket来建 ...

  8. Java利用TCP编程实现简单聊天室

    前言: 本文是我在学习尚学堂JAVA300集第二季网络编程部分仿照视频内容实现而成 具体可以去尚学堂官网观看视频学习 一.实现思路 实现聊天室的最核心部分就是JAVA的TCP网络编程. TCP 传输控 ...

  9. 手动搭建I/O网络通信框架4:AIO编程模型,聊天室终极改造

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 第三章:手动搭建I/O网络通信框架3:NI ...

  10. 网络编程-基于Websocket聊天室(IM)系统

    目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...

随机推荐

  1. Linux 内核音频数据传递主要流程 (下)

    来而不往非礼也.前面看到了用户空间应用程序和 DMA buffer 之间交换数据,并更新 runtime->control->appl_ptr 指针的过程,这里看一下硬件设备驱动程序在完成 ...

  2. PHP写一个 Api接口需要注意哪些?考虑哪些?

    随着互联网的飞速发展,前后端分离的开发模式越来越流行.编写一个稳定.可靠和易于使用的 API 接口是现代互联网应用程序的关键.本文将介绍在使用 thinkphp6 框架开发 API 接口时需要注意的要 ...

  3. 在编写API接口的技术文章时应注意的内容

    编写API接口的技术文章时,建议包含以下内容: 1. 简介:介绍API接口的目的和作用,以及所属的项目或服务. 2. 接口描述:详细描述API接口的功能和使用方法,包括输入参数.输出结果和可能的错误码 ...

  4. PGO in Go 1.21

    原文在这里. 由 Michael Pratt 发布于 2023年9月5日 在2023年早些时候,Go 1.20发布了供用户测试的概要版本的基于性能分析的优化(PGO).经过解决预览版已知的限制,并得益 ...

  5. 【Azure Batch】在批处理的Task中如何让它执行多个CMD指令呢

    问题描述 根据Azure Batch的入门文档(使用 Azure 门户创建 Batch 帐户并运行作业 : https://docs.azure.cn/zh-cn/batch/quick-create ...

  6. Java 21 新特性:switch的模式匹配

    在之前的Java 17新特性中,我们介绍过关于JEP 406: switch的模式匹配,但当时还只是关于此内容的首个预览版本.之后在JDK 18.JDK 19.JDK 20中又都进行了更新和完善.如今 ...

  7. macbook-键盘连击问题002

    https://support.apple.com/zh-cn/HT205662 如何清洁 MacBook 或 MacBook Pro 的键盘 如果您的 MacBook(2015 年及更新机型)或 M ...

  8. 2020/5/8—cf,我裂开来

    呜呜呜我爆零了呜呜呜ljll 嗯T1T2防爆零的没了呜呜呜在此纪念可怜的yjz大佬21发AC 太惨了(逃 先来说说我们都有些啥题目吧... T1 嗯,裂开了,当场裂开我一看!桶排!然后实现,嗯?嗯!嗯 ...

  9. Mac OS安装Python的pip

    最近牛牛的同学在学习python,但当他使用numpy时出现了报错(。•́︿•̀。) 原因为他的python没有numpy这个库(这个故事很典).然鹅雪上加霜的是,他的电脑是Mac,没有Windows ...

  10. PTA乙级1044C++(手动打表hhh)

    1044 火星数字 (20 分) 火星人是以 13 进制计数的: 地球人的 0 被火星人称为 tret. 地球人数字 1 到 12 的火星文分别为:jan, feb, mar, apr, may, j ...