python socket编程 实现简单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

聊天效果如下

 

转载于:https://www.cnblogs.com/wuxie1989/p/7204887.html

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现基于P2P的局域网即时通信系统,你可以使用Python的socket模块和线程模块。以下是一个简单的示例程序: ```python import socket import threading # 服务器IP和端口号 SERVER_IP = '127.0.0.1' SERVER_PORT = 8080 # 创建socket对象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定IP和端口号 server_socket.bind((SERVER_IP, SERVER_PORT)) # 监听连接 server_socket.listen(5) # 客户端列表 clients = [] # 处理客户端连接 def handle_client_connection(client_socket): while True: # 接收客户端消息 message = client_socket.recv(1024).decode() # 广播消息给所有客户端 for c in clients: c.send(message.encode()) # 如果客户端退出,移除客户端 if not message: clients.remove(client_socket) client_socket.close() break while True: # 等待客户端连接 client_socket, address = server_socket.accept() # 添加客户端到列表 clients.append(client_socket) # 启动新线程处理客户端连接 client_thread = threading.Thread(target=handle_client_connection, args=(client_socket,)) client_thread.start() ``` 此程序创建一个基于TCP协议的服务器,监听指定的IP和端口号。当客户端连接到服务器时,服务器将该客户端添加到客户端列表中,并启动一个新线程处理该客户端连接。每个客户端连接将接收到所有其他客户端发送的消息。当客户端退出时,服务器将该客户端从客户端列表中移除。 要使用此程序,你需要在每个客户端上运行一个客户端程序,该程序将连接到服务器,并发送和接收消息。你可以使用Python的socket模块创建客户端程序。以下是一个简单的示例程序: ```python import socket import threading # 服务器IP和端口号 SERVER_IP = '127.0.0.1' SERVER_PORT = 8080 # 创建socket对象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接到服务器 client_socket.connect((SERVER_IP, SERVER_PORT)) # 处理服务器消息 def handle_server_message(): while True: # 接收服务器消息 message = client_socket.recv(1024).decode() # 输出消息 print(message) # 启动新线程处理服务器消息 server_thread = threading.Thread(target=handle_server_message) server_thread.start() while True: # 发送消息给服务器 message = input() client_socket.send(message.encode()) ``` 此程序创建一个基于TCP协议的客户端,连接到指定的IP和端口号的服务器。当客户端连接到服务器时,客户端将启动一个新线程处理服务器发送的消息。主线程将等待用户输入消息并将其发送到服务器。 此示例程序只是一个简单的局域网即时通信系统,你可以根据需要修改和扩展它。例如,你可以添加身份验证、加密、文件传输等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值