python socket编程 实现简单p2p聊天程序
目标是写一个python的p2p聊天的项目,这里先说一下python socket的基础课程
一、Python Socket 基础课程
Socket就是套接字,作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一 般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原 意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务

Socket连接的步骤
(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接 字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
二、服务端程序
因为很喜欢看三体,所以这个服务端就起名叫红岸,红岸基地的主要作用就是作为server端来使用,转发双方的通信,现在是调试阶段,先使用socket写单线程的,以后会使用socketserver或者多线程来重新写一个
先建立一个连接列表
# -*- coding: utf-8 -*-
import select
import socket inBufSize = 4096
outBufSize = 4096
CONNECTION_LIST = []
构造函数
def __init__(self,port=5247):
# todo 使用socketserver来写
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serverSocket.bind(('', port))
self.serverSocket.listen(5)
print "server wait for connect...."
self.socketsMap = {} # socket session字典 id : socket
self.idMap = {} #socket session 字典 socket:id
CONNECTION_LIST.append(self.serverSocket)
socketsMap和idMap是分别建立这id和socket之间的对应字典,P2P聊天的时候通过socket来找发送者id和通过接受者id来找socket
主要的处理函数是这样的
def socet_handle(self):
while 1:
# Get the list sockets which are ready to be read through select
read_sockets, write_sockets, error_sockets = select.select(CONNECTION_LIST, [], [])
for sock in read_sockets:
# New connection
if sock == self.serverSocket:#用户通过主socket(即服务器开始创建的 socket,一直处于监听状态)来登录
# Handle the case in which there is a new connection recieved through server_socket
sockfd, addr = self.serverSocket.accept()
id = sockfd.recv(100)
self.login(id,sockfd)
else:
self.chat(sock)
通过select来监听所有的连接,select是一个非阻塞的监听程序,监听文件的读,写,错误,函数用法是select.select(readable_iterable,writeble_iterable,error_iterable,timeout).
如果用户是使用主socket(一直在监听的端口,用户登录时要连接到这个端口,然后再在别的端口通信),就要登录函数
登录函数如下
def login(self,id,sock):#新用户登录
print "%s login"%id
self.socketsMap[id] = sock
self.idMap[sock] = id
sock.send('hello %s,you login successed'%id)
CONNECTION_LIST.append(sock)#要在这里把socket加进来才行
在CONNECTION_LIST中把会话加进去,然后返回一个问候信息
聊天和广播程序
def chat(self,sock):#点对点聊天,发送消息格式id||信息
try:
data = sock.recv(inBufSize)
except Exception:
sock.send("remote is offline")
sock.close()
else:
remote_id = data.split('||')[0]
message = data.split('||')[1]
print "id = %s,message = %s"%(remote_id,message)
local_id = self.idMap[sock]
if remote_id == 'all':
self.broadcast(local_id,message)
else:
self.p2psend(local_id,message,remote_id) def p2psend(self,local_id,message,remote_id):
remote_socket = self.socketsMap[remote_id]
message_send = "%s said : %s" % (local_id, message)
try:
remote_socket.sendall(message_send)
except Exception,e:
print e
remote_socket.close()
CONNECTION_LIST.remove(remote_socket) def broadcast(self,local_id,message):
for sock in CONNECTION_LIST:
if sock == self.serverSocket:
continue
else:
try:
message_send = "%s said : %s" % (local_id, message)
sock.send(message_send)
except Exception,e:
print e
sock.close()
CONNECTION_LIST.remove(sock)
continue
服务端的完全体如下
# -*- coding: utf-8 -*-
import select
import socket inBufSize = 4096
outBufSize = 4096
CONNECTION_LIST = [] class ChatServer:
def __init__(self,port=5247):
# todo 使用socketserver来写
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serverSocket.bind(('', port))
self.serverSocket.listen(5)
print "server wait for connect...."
self.socketsMap = {} # socket session字典 id : socket
self.idMap = {} #socket session 字典 socket:id
CONNECTION_LIST.append(self.serverSocket) def login(self,id,sock):#新用户登录
print "%s login"%id
self.socketsMap[id] = sock
self.idMap[sock] = id
sock.send('hello %s,you login successed'%id)
CONNECTION_LIST.append(sock)#要在这里把socket加进来才行 def chat(self,sock):#点对点聊天,发送消息格式id||信息
try:
data = sock.recv(inBufSize)
except Exception:
sock.send("remote is offline")
sock.close()
else:
remote_id = data.split('||')[0]
message = data.split('||')[1]
print "id = %s,message = %s"%(remote_id,message)
local_id = self.idMap[sock]
if remote_id == 'all':
self.broadcast(local_id,message)
else:
self.p2psend(local_id,message,remote_id) def p2psend(self,local_id,message,remote_id):
remote_socket = self.socketsMap[remote_id]
message_send = "%s said : %s" % (local_id, message)
try:
remote_socket.sendall(message_send)
except Exception,e:
print e
remote_socket.close()
CONNECTION_LIST.remove(remote_socket) def broadcast(self,local_id,message):
for sock in CONNECTION_LIST:
if sock == self.serverSocket:
continue
else:
try:
message_send = "%s said : %s" % (local_id, message)
sock.send(message_send)
except Exception,e:
print e
sock.close()
CONNECTION_LIST.remove(sock)
continue def socet_handle(self):
while 1:
# Get the list sockets which are ready to be read through select
read_sockets, write_sockets, error_sockets = select.select(CONNECTION_LIST, [], [])
for sock in read_sockets:
# New connection
if sock == self.serverSocket:#用户通过主socket(即服务器开始创建的 socket,一直处于监听状态)来登录
# Handle the case in which there is a new connection recieved through server_socket
sockfd, addr = self.serverSocket.accept()
id = sockfd.recv(100)
self.login(id,sockfd)
else:
self.chat(sock) def main(self):
self.socet_handle()
self.serverSocket.close() if __name__ == '__main__':
chat_server_obj = ChatServer()
chat_server_obj.main()
三、客户端程序
客户端程序的名字是叶文洁和监听员1379,不要回答!不要回答!不要回答!
主要就是使用select来监听sys.stdin和socket,来活儿了就要及时处理
def socket_handler(self):
while 1:
rlist = [sys.stdin, self.client_socket] # 接收列表
read_list, write_list, error_list = select.select(rlist, [], [], 2)
for sock in read_list:
# incoming message from remote server
if sock == self.client_socket:
data = sock.recv(4096)
if not data:
print '\nDisconnected from chat server'
sys.exit()
else:
# print data
sys.stdout.write(data)
self.prompt() # user entered a message
else:
msg = sys.stdin.readline()
remote_id = raw_input("Please input remote id:")
msg_send = "%s||%s"%(remote_id,msg)
self.client_socket.send(msg_send)
self.prompt()
快吃中午饭了,就不详细说了,也没什么好详细说的,很简单,客户端完全体如下,叶文洁的id是1,监听员1379的id是2,后边可以改成手动指定的,在群聊里面加上托马斯维德和程心
# -*- coding:utf-8 -*-
import socket, select, string, sys
HOST = '127.0.0.1'
PORT = 5247
ID = '' class ChatClient:
def __init__(self):
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.settimeout(2)
self.connect() def connect(self):
try:
self.client_socket.connect((HOST, PORT))
self.client_socket.send(ID)
except Exception,e:
print 'Unable to connect because of %s'%e
sys.exit()
else:
print 'Connected to remote host. Start sending messages'
self.prompt() def prompt(self):
sys.stdout.write('\n<You> ')
sys.stdout.flush() def socket_handler(self):
while 1:
rlist = [sys.stdin, self.client_socket] # 接收列表
read_list, write_list, error_list = select.select(rlist, [], [], 2)
for sock in read_list:
# incoming message from remote server
if sock == self.client_socket:
data = sock.recv(4096)
if not data:
print '\nDisconnected from chat server'
sys.exit()
else:
# print data
sys.stdout.write(data)
self.prompt() # user entered a message
else:
msg = sys.stdin.readline()
remote_id = raw_input("Please input remote id:")
msg_send = "%s||%s"%(remote_id,msg)
self.client_socket.send(msg_send)
self.prompt() if __name__ == '__main__':
chat_client_obj = ChatClient()
chat_client_obj.socket_handler()
githu地址
https://github.com/wuxie2015/tri_body_chat
聊天效果如下


python socket编程 实现简单p2p聊天程序的更多相关文章
- [JavaWeb基础] 024.Socket编程之简单的聊天程序
1.Socket的简介 1)什么是Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket ...
- Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程
SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...
- Java网络编程以及简单的聊天程序
网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...
- 基于socket实现的简单的聊天程序
记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上. 一个偶然的机会,第二次使用socket做点事情.先看聊天服务器端的实现: 服务器端要实现以下功能: ...
- Python Socket 编程——聊天室示例程序
上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...
- Python Socket 编程——聊天室演示样例程序
上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...
- 简单的聊天程序,主要用到的是Socket
服务端: import java.io.*; import java.net.*; import java.util.*; public class ChatServer { boolean stat ...
- C#编写简单的聊天程序
这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编 ...
- python socket 实现的简单http服务器
预备知识: 关于http 协议的基础请参考这里. 关于socket 基础函数请参考这里. 关于python 网络编程基础请参考这里. 一.python socket 实现的简单http服务器 废话 ...
随机推荐
- MySQL性能优化(四)-- MySQL explain详解
前言 MySQL中的explain命令显示了mysql如何使用索引来处理select语句以及连接表.explain显示的信息可以帮助选择更好的索引和写出更优化的查询语句. 一.格式 explain + ...
- 告别C#,进入了下一个阶段的学习啦
嘿嘿,今天我们结束了C#的基础的学习,开始啦第二个阶段的学习,就是对SQL Server的学习.今天又是一个周一,又是一个新的开始,感觉我们都是一周一周的计算,而不是每天到这个点就是告别了今天的生活啦 ...
- Android项目结构介绍
src/存放Java源代码gen/中存放系统自动生成的配置文件Android 4.4.2下包含android.jar文件,这是一个Java归档文件,其中包含构建应用程序所需的所有的Android SD ...
- 腾讯正式开源高性能超轻量级 PHP 框架 Biny
概况 Biny是一款高性能的超轻量级PHP框架 遵循 MVC 模式,用于快速开发现代 Web 应用程序 Biny代码简洁优雅,对应用层,数据层,模板渲染层的封装简单易懂,能够快速上手使用 高性能,框架 ...
- 开发人员必读openstack网络基础2:交换机、路由器、DHCP
我们在使用openstack的过程中,会遇到创建虚拟机路由器.交换机等,那么1.他们的作用到底是什么?2.DHCP为什么会产生,它的作用是什么? 个人总结:交换机:一般用在同一网段,工作在数据链路层, ...
- 开源的PaaS方案:在OpenStack上部署CloudFoundry (二)部署OpenStack
硬件要求 安装OpenStack 1 安装CentOS 65系统并清空iptables防火墙规则 2 安装系统需要的工具包包括Openstack依赖的和CloudFoundry依赖的 3 安装EPEL ...
- LeetCode——Ugly Number
Description: Write a program to check whether a given number is an ugly number. Ugly numbers are pos ...
- 静态资源的gzip
1.项目中,接触到gzip.未压缩的文件和压缩后的文件的比例可能达到:3:1.所以,gzip是网络中文件高速传输的很好方法. 2.一般js.css.html文件都会在后端进行gzip.当浏览器请求这些 ...
- 自行颁发不受浏览器信任的SSL证书
ssh登陆到服务器上,终端输入以下命令,使用openssl生成RSA密钥及证书. # 生成一个RSA密钥 $ openssl genrsa -des3 -out 33iq.key 1024 # 拷贝一 ...
- 310实验室(六)CMake学习心得
树形结构方式布局. OTL 中每一个文件中的CMakeLists.txt 有不同的作用:按查看文件的先后顺便进行分层理解, 根文件即第一次 中的.txt是 启用 CMAKE_MODULE_PATH模板 ...