目标是写一个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服务器 废话 ...
随机推荐
-
java socket 一个服务器对应多个客户端,可以互相发送消息
直接上代码,这是网上找的demo,然后自己根据需求做了一定的修改.代码可以直接运行 服务器端: package socket; import java.io.BufferedReader; impor ...
-
Nutch+Hadoop集群搭建
转载自:http://www.open-open.com/lib/view/open1328670771405.html 1.Apache Nutch Apache Nutch是一个用于网络搜索 ...
-
jQuery使用(十二):工具方法之ajax的无忧回调(优雅的代码风格)
jQuery.ajax()方法的应用 jQuery.ajax()的无忧回调(优雅的代码风格) 一.jQuery.ajax()方法的应用 jQuery.ajax()实质上就是在ajax的基础上进行了封装 ...
-
pycharm 如何进行全部搜索
界面里面先按ctrl F 弹出搜索页面 在搜索框内连续按两次shift shift可以搜索全文
-
LeetCode(23):合并K个排序链表
Hard! 题目描述: 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2-> ...
-
sqlserver2014内存数据库特性介绍
sql server 2014提供了众多激动人心的新功能,但其中我想最让人期待的特性之一就要算内存数据库了,下面就简单介绍一下sql server 2014的内存数据库的一些特性 相信大家对内存数 ...
-
C++ operator关键字详解
C++中的operator主要有两个作用,一是操作符的重载,一是自定义对象类型的隐式转换. 类型转换操作符(type conversion operator)是一种特殊的类成员函数,它定义将类类型值转 ...
- Nginx负载均衡 ssl原理 生成ssl密钥对 Nginx配置ssl
-
登陆跳板机每天只输入一次token的方法——ssh clone session
自从跳板机升级后,无所不在的token让小PE很是恼火,于是有了这篇文章@_@ Linux or Mac篇 在Fedora或者Mac下很简单,修改~/.ssh/config文件,没有的话,就新建一个( ...
-
linux centos5.8装yum安装mysql
默认的yum安装mysql都是5.1版本的 想要安装5.7的可以进行配置rpm包进行, mysql5.7安装路径 下面是默认的5.1安装路径 首先我们在使用yum安装的的时候会默认使用最新安装的,最 ...