目标是写一个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聊天程序的更多相关文章

  1. [JavaWeb基础] 024.Socket编程之简单的聊天程序

    1.Socket的简介 1)什么是Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket ...

  2. Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程

    SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...

  3. Java网络编程以及简单的聊天程序

    网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...

  4. 基于socket实现的简单的聊天程序

    记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上. 一个偶然的机会,第二次使用socket做点事情.先看聊天服务器端的实现: 服务器端要实现以下功能:     ...

  5. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  6. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  7. 简单的聊天程序,主要用到的是Socket

    服务端: import java.io.*; import java.net.*; import java.util.*; public class ChatServer { boolean stat ...

  8. C#编写简单的聊天程序

    这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编 ...

  9. python socket 实现的简单http服务器

    预备知识: 关于http 协议的基础请参考这里. 关于socket 基础函数请参考这里. 关于python 网络编程基础请参考这里. 一.python socket 实现的简单http服务器   废话 ...

随机推荐

  1. 《C++ Primer Plus》14.2 私有继承 学习笔记

    C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保 ...

  2. PyQt4关闭窗口

    一个显而易见的关闭窗口的方式是但集标题兰有上角的X标记.接下来的示例展示如何用代码来关闭程序,并简要介绍Qt的信号和槽机制. 下面是QPushButton的构造函数,我们将会在下面的示例中使用它. Q ...

  3. LNMP 配置二级域名

    准备: 已备案的主域名,例如:www.test.com 拥有自己的服务器 服务器环境 LNMP 目标: 配置一个二级域名: bbs.test.com 1 登录域名后台(阿里为例) 记录类型: A 主机 ...

  4. Linux下多任务间通信和同步-mmap共享内存

    Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...

  5. js 生成二维码图片

    1.用纯JavaScript实现的微信二维码图片生成器 QRCode.js是javascript实现二维码(QRCode)制作生成库. QRCode.js有着良好的跨浏览器兼容性(高版本使用HTML5 ...

  6. 几行小代码,将Testlink的xml用例导入至excel

    最近在使用Testlink时,发现导入的用例是xml格式,且没有合适的工具转成excel格式,xml使用excel打开显示的东西也太多,网上也有相关工具转成csv格式的,结果也不合人意. 那求人不如尔 ...

  7. Testlink在CentOS、windows安装

    有幸在CentOS\windows上都安装过Teslink程序,总结一下.如下: 一.CentOS安装: 1.安装包需要: xampp xampp-linux-x64-5.6.3-0-installe ...

  8. 动态设置progressBar的进度

    progressDrawable = this.getResources().getDrawable(R.drawable.image); progressDrawable.setBounds(mSe ...

  9. java jar命令及补丁方法

    用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...选项: -c 创建新档案 -t ...

  10. ThinkPHP简单结构介绍!

    thinkPHP简单结构介绍: application : 应用 extend:扩展 扩展内库 public:入口文件 index.php 在里面 runtime:缓存文件(里面的文件可以随便删除) ...