目标是写一个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. php学习一:语法规则

    1.书写规则 在html中嵌入php的时候,需要有结束语,即<?php ...?>,在靠近结束符号的最后一个语句可以不用写分号: 但是在单独的php中,最后可以不用以?>来结尾; 2 ...

  2. Android 使用线性布局LinearLayout和Button实现一个点红块游戏

    这个游戏的功能类似打地鼠. 项目地址:https://github.com/moonlightpoet/RedBlock 程序下载试玩地址:https://github.com/moonlightpo ...

  3. FTP新建文件夹访问

    今天在远程服务器上添加了文件夹,本来还想着FTP打开看看,结果竟然发现没有这个文件夹访问 想了一下,感觉应该是FTP访问的文件设置,只有FTP设置了的文件夹才能有显示

  4. JS中保留小数位数

    一.1.2.toFixed(2)

  5. 解决instance中文命名导致nova list报错问题

    当创建instance之后,如果使用英文命名,执行nova list的时候,无问题,但是,如果instance中出现中文,执行nova list的时候,会报以下错误: [root@controller ...

  6. HTML5文件拖拽上传记录

    JS文件: var FileName = ""; var FileStr = ""; (function () { function $id(id) { ret ...

  7. 【顽固BUG】Visual Studio 2015 + TestDriven.NET-3.8.2860_Personal_Beta 调用的目标发生了异常。

    前言 突然怎么弄也无法断点调试了 输出如下: ------ Test started: Assembly: Server5.V2.dll ------ 调用的目标发生了异常. 而且网站运行提示: -- ...

  8. Windows Phone 自定义一个启动画面

    1.新建一个UserControl <UserControl x:Class="LoadingPage.PopupSplash" xmlns="http://sch ...

  9. 微信开发(3):微信公众号发现金红包功能开发,利用第三方SDK实现(转)

    最近需求是 用户兑换微信红包,需要一些验证,加密,以及证书: 工欲善其事必先利其器 感谢前辈的微信SDK 已经维护三年了,还在维护中! 官方文档走一波 文档还是一如既往的 坑人啊,写的很简单,对简单明 ...

  10. phpStorm 显示行号