目标是写一个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. EOF ---shell编程

    转自:http://blog.163.com/njut_wangjian/blog/static/1657964252013112152418345/ 在shell编程中,”EOF“通常与”<& ...

  2. linux系统输入法设置

    首先是要安装了中文输入法,下面以搜狗为例. 2 从system settings 进入language support ,在keyboard input method system 中是看不到自己安装 ...

  3. UART简介

    经常遇到初学者,对单片机串行通讯出了问题不知道如何办的情况.其实最有效的调试方法是用示波器观察收发数据的波形.通过观察波形可以确定以下情况: 1.数据是否接收或发送: 2.数据是否正确: 3.波特率是 ...

  4. DiscuzX的目录权限设置1

    经常有朋友遇到Discuz目录权限设置出错的问题,网上千奇百怪的教程非常多,所谓的终极安全的教程更是满天飞,各种所谓的安全加强软件也随处可见,可实际过程中发现,老手用不上,新手则只会因为这些东西徒增麻 ...

  5. 动态调整UITableViewCell高度的实现方法

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPa ...

  6. PyQt4发射信号

    继承自QtCore.QObject的对象均可以发射信号.如果我们单击一个按钮,那么一个clicked()信号就会被触发.下面的示例演示如何手动发射一个信号. #!/usr/bin/python # - ...

  7. AndroidのBuild工具之Ant动手实践

    好久没有写博客了,没半年也应该有几个月了.在工作上的项目遇到过很多问题或者说积累了不少经验,曾经都蛮想发到博客留个纪念什么的,不求可以为别人获得点经验技巧,只求在多年后遇到同样的问题可以找到个记录.但 ...

  8. poj_1236 强连通分支

    题目大意 有N个学校,这些学校之间用一些单向边连接,若学校A连接到学校B(B不一定连接到A),那么给学校A发一套软件,则学校B也可以获得.现给出学校之间的连接关系,求出至少给几个学校分发软件,才能使得 ...

  9. 【Thinkphp5】结合layer弹窗 定制操作结果页面

    1 打开应用公共文件页面    appliction/common.php,编写以下代码 注意: 成功消息的绿色背景部分是iframe 框架写法,如果是普通页面.就吧parent去除,改为: self ...

  10. setTimeout原来有这种用途

    setTimeout有两个参数,第一个是需要执行的函数,第二个是将该函数推入UI队列的时间. 需要注意的两点: 1.第二个参数中设置的时间,是从执行setTimeout开始计算,而不是从整个函数执行完 ...