1. 程式人生 > >Python網路程式設計----實現簡單的多人聊天室

Python網路程式設計----實現簡單的多人聊天室

還是用UDP,socket作為主體來實現,之前我們已經實現過單對單socket通訊,這次想實現群發功能

原理其實就是一臺伺服器在負責分配轉發資料,來達成廣播的效果,這些思路其實也差不多

但是多人聊天沒有這麼強的規整性,你可能沒等到A的訊息,就要去和B說話了,多執行緒就可以實現這一點

主要就是依靠threading模組

你可以理解為,我們建立了一個類似於陣列的空間,來存放我們所有要執行的工作,然後同時開始,然後通過阻塞父程序來等待子程序結束,這就是多執行緒工作

直接上程式碼段好了,用txt和字典可以偽造一個非常非常破的聊天室,自己其實感覺做的挺垃圾的,畢竟最後的成品,本地就算是儲存了個人資訊,要群發訊息的話,還需要伺服器存放的字典的values來追蹤各個地址,完全是脫節的,唉,菜到落淚,不會資料庫,也沒有介面,不過總算是熟悉了一波字典的操作,爭取早日用上json

SERVER:

import json
import socket

name_dict={}           #空字典

def register(data,client_addr):
    f=open("members.txt",'a+')
    data=data[9::]
    key=data.decode('utf-8')
    line=f.readline().strip()
    print(line)
    result=line.find(key)
    if result >=0:
        s="your information has been used, please register again"
        server.sendto(s.encode('utf-8'),client_addr)
        f.close()
        return 1

    while line:
        line = f.readline().strip()
        result=line.find(key)
        if result>=0:
            s="your information has been used, please register again"
            server.sendto(s.encode('utf-8'),client_addr)
            f.close()
            return 1

    #print(key[:8:])
    #print(key[9::])
    f.write('name/password:%s\n' %key)
    s='welcome,now you can login'
    server.sendto(s.encode('utf-8'),client_addr)
    f.close()
    return 0




def login(data,client_addr):
    f=open("members.txt",'r+')
    data=data[9::]
    #print(data)
    key=data.decode('utf-8')
    print(key)
    #data,client_addr = server.recvfrom(BUFSIZE)            #從緩衝區讀取1024個位元組,The return value is a pair (bytes, client_address)
    #try:
    line=f.readline().strip()
    result=line.find(key)
    print(result)
    if result >=0:
        name_dict[key]=client_addr
        s='wait for you for a long time, what do you want to tell to others'
        server.sendto(s.encode('utf-8'),client_addr)  
        f.close()        

        return 1    

    while line:
        line=f.readline().strip()
        result=line.find(key)
        if result >=0:
            name_dict[key]=client_addr
            s='wait for you for a long time, what do you want to tell to others'
            server.sendto(s.encode('utf-8'),client_addr)     
            f.close()        
            return 1  
                
    s='wrong password or name, goodbye'                    #make client closed
    server.sendto(s.encode('utf-8'),client_addr)

    f.close()        
    return 0


def qunfa111(data,client_addr):
    #data=data.decode('utf-8')
    data=data[9::]
    flag=0
    for value in name_dict.values():
        if value==client_addr:
            flag=1
            for value in name_dict.values():
                if value==client_addr:
                    continue
                server.sendto(data,value)
    if flag==0:
        server.sendto(b'please login first',client_addr)
    return

def sifa1111(data,client_addr,toname):
    toname=data[9:28:]
    print(toname)
    data2=data[28::]
    print(data2)
    flag=0
    print(name_dict)
    for value in name_dict.values():
        if value==client_addr:
            flag=1
            for key in name_dict.keys():
                if key==toname:
                    server.sendto(data2,name_dict[toname])
                    server.sendto(b'OK',client_addr)
                    return
            flag=2
            if flag==2:
                server.sendto(b'who is he?',client_addr)
                return
    if flag==0:
        server.sendto(b'please login first',client_addr)
    return

                
#-----------------------------------------------------------------------------------------------------------------------------------------------------

BUFSIZE = 1024                                             #規定緩衝區的大小
ip_port = ('127.0.0.1', 9999)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # udp協議
server.bind(ip_port)
print('Listening at {}'.format(server.getsockname))        #getsockname()可以獲取套接字目前繫結的IP地址即埠,返回的是一個二元組
#s='welcome, what do you want to do: QUIT,register,login'
#server.sendto(s.encode('utf-8'),client_addr)
while True:
    data,client_addr = server.recvfrom(BUFSIZE)            #從緩衝區讀取1024個位元組,The return value is a pair (bytes, client_address)
    print(data[:8:])
    if data[:8:]==b'Leaving~':
        server.sendto(b'see you later',client_addr)
        for key in name_dict.keys():
            if name_dict[key]==client_addr:
                del name_dict[key]
        continue
    
    elif data[:8:]==b'register':
        #print(data)
        n=1
        while(n):
            n=register(data,client_addr)
    
    elif data[:8:]==b'logining':
        #data=data[9::]
        login(data,client_addr)

    elif data[:8:]==b'sifa1111':
        sifa1111(data,client_addr,data[9:12:])   #名字暫時只能3個字元
    
    elif data[:8:]==b'qunfa111':
        qunfa111(data,client_addr)
server.close()

CLIENT

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket
import threading
BUFSIZE = 1024
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)   # udp協議
print('welcome, what do you want to do: Leaving~,register,logining')
ip_port = ('127.0.0.1', 9999)

def recv():
    while(True):
        client.connect(ip_port)
        data,server_addr= client.recvfrom(BUFSIZE)
        if data==b'see you later':                             #輸入QUIT即可斷開連線
            print('Data recived from sever:',data,server_addr)
            client.close()
        print('Data recived from sever:',data.decode('gb2312','ignore'),server_addr)

def send():
    while(True):
        msg = input(">> ").strip()                             #strip() 方法用於移除字串頭尾指定的字元(預設為空格或換行符)或字元序列
        client.sendto(msg.encode('utf-8'),ip_port)             # 以utf-8編碼對u進行編碼,獲得bytes型別物件


threads=[]
t1 = threading.Thread(target=send)
threads.append(t1)
t2 = threading.Thread(target=recv)
threads.append(t2)

for i in range(len(threads)):    #啟動執行緒
	threads[i].start()

threads[0].join()   #send未結束不可以停止

群發問題不大,但是私聊還有問題,調對齊很麻煩,先不弄了