python 简单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 = ‘1‘

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

聊天效果如下

时间: 2024-10-14 14:43:06

python 简单p2p聊天程序的相关文章

从一个简单的聊天程序SimpleChat看VPN技术

SimpleVPN写好了以后,感觉比较简单,我觉得只有简单的东西才经得起折腾,才能全民折腾,所以说SimpleVPN还不够简单,本文来一个更加简单的,展示一个超级简单的点对点聊天程序,而且还带简单加密哦.顺便,我们再来看下,到底什么是VPN以及怎样实现它.       QQ如今才刚刚行过成年之礼,典型的90后00前,却早已到了后浪把前浪拍到岸边的砍儿,果不其然,被10后的微信给逆袭了...好在都是腾讯的,这就把竞争收敛到了公司内部,不然这将意味着一个巨人的倒下,太可怕了.多年前,很多人逆向过QQ

使用Ajax long polling实现简单的聊天程序

关于web实时通信,通常使用长轮询或这长连接方式进行实现. 为了能够实际体会长轮询,通过Ajax长轮询实现了一个简单的聊天程序,在此作为笔记. 长轮询 传统的轮询方式是,客户端定时(一般使用setInterval)向服务器发送Ajax请求,服务器接到请求后马上返回响应信息.使用这种方式,无论客户端还是服务端都比较好实现,但是会有很多无用的请求(服务器没有有效数据的时候,也需要返回通知客户端). 而长轮询是,客户端向服务器发送Ajax请求,服务器接到请求后保持住连接,直到有新消息才返回响应信息,客

C#编写简单的聊天程序(转)

这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编程基础(篇外篇).聊天程序的实现模式.程序实现. 程序的分析与设计 1.明确程序功能 如果大家现在已经参加了工作,你的经理或者老板告诉你,“小王,我需要你开发一个聊天程序”.那么接下来该怎么做呢?你是不是在脑子里有个雏形,然后就直接打开VS2005开始设计窗体,编写代码了呢?在开始之前,我们首先需要

基于Java实现hello/hi简单网络聊天程序

目录 Socket简要阐述 Socket的概念 Socket原理 hello/hi的简单网络聊天程序实现 服务器端 客户端 程序执行结果 跟踪分析调用栈 & Linux API对比 创建ServerSocket 调用栈图示 源码分析 Socket绑定 调用栈图示 源码分析 Socket监听 调用栈图示 源码分析 Socket Accept 调用栈图示 源码分析 Java Socekt API与Linux Socket API 参考链接 Socket简要阐述 Socket的概念 Socket的英文

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

网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编程简要概述: 网络编程实质实质就是两个(或多个)设备(例如计算机)之间的数据传输.而要实现两台计算机通过互联网连接进行数据传输,必输要满足计算机网络的5层协议(物理层,数据链路层,网络层,运输层,应用层):当然有划分可能不同,但现在大家比较容易接受理解的是五层模型.而其中前三层物理层,数据链路层以及

UDP&mdash;Socket,套接字聊天简单的聊天程序。

思路:(发送端) 1.既然需要聊天.就应该怎么建立聊天程序,,DatagramSocket对象http://www.w3cschool.cc/manual/jdk1.6/ DatagramSocket dgSocket = new DatagramSocket(); 2.那么发给谁?怎么打包数据.DatagramPacket. 代码如下DatagramPacket对象API文档链接http://www.w3cschool.cc/manual/jdk1.6/ 具体查看集体代码: //创建数据包 b

用c#开发安卓程序 (xamarin.android)系列之二 简单的聊天程序

networkcomm.net 网络通信框架来自于英国剑桥,其开源版本2.3.1 中自带了一个编写android的例子,可以很好的帮助我们入门. 此示例的功能,是在2个安卓手机上,输入对方的IP和端口,能够实现聊天功能. 把代码放上,供大家一览 using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; using Android.Widget; using

简单的聊天程序

//QQ聊天程序的建立网络流类 import java.net.*; import java.io.*; public class Neter { private BufferedReader br; private PrintWriter pw; public Neter(Socket socket){ try{ InputStream is=socket.getInputStream(); InputStreamReader isr=new InputStreamReader(is); br

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

记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上. 一个偶然的机会,第二次使用socket做点事情.先看聊天服务器端的实现: 服务器端要实现以下功能:      1.启动服务,开启监听      2.持续不断地接收消息      3.发送消息 启动服务,创建监听socket,绑定Ip和端口: 1 /// <summary> 2 /// 启动服务 3 /// </summary> 4 private void Start() 5 { 6 so