概念html
函數解釋(python import socket)python
socket建立分析 先分析一下哪些代碼是堵塞的web
啊,好煩,習慣單進程的我真是醉了,這讓人咋寫! (╯‵□′)╯︵┻━┻ 首先咱們要先分析一下咱們要創建什麼樣的對話redis
_(:з」∠)_
# Server.py
import socket
import sys,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(("127.0.0.1",8000))
s.listen(5)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
conn,address=s.accept()
#開啓子進程,找兒子幫忙
pid=os.fork()
if(pid>0):
#讀取輸入,發送給client
while 1:
msg=sys.stdin.readline()
if msg == "quit":
sys.exit()
conn.send(bytes(msg,encoding="utf-8"))
else:
while 1:
log_file=open('./client_input.log','a')
msg=conn.recv(1024)
print ("client:"+msg.decode('utf-8'))
log_file.write(msg.decode('utf-8'))
if msg == "bye":
log_file.close()
sys.exit()
# Client.py
import socket
import sys,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",8000))
pid=os.fork()
if(pid>0):
while 1:
msg=sys.stdin.readline()
if msg == "quit":
sys.exit()
s.send(msg.encode('utf-8'))
else:
while 1:
log_file=open('./server_input.log','a')
msg=s.recv(1024)
print ("server:"+msg.decode('utf-8'))
log_file.write(msg.decode('utf-8'))
if msg == "bye":
log_file.close()
sys.exit()
複製代碼
全部人都知道咱們的服務端地址和端口
,他們不知道彼此的地址和端口
,因此,套接字的創建,只可能存在與服務器與客戶端之間
,客戶端與客戶端之間是沒法創建鏈接的
2.這樣咱們就有了一個前提:咱們的服務端能夠與全部人創建鏈接,若是想要作一個聊天室,須要哪些功能呢?
一個用戶發出消息,發給了服務端,多人聊天室要幹什麼?固然是讓其餘人接受到這我的發出的消息,一句話歸納,將一我的發給咱們服務端的消息,廣播給聊天室裏的其餘人
編程
給單一客戶端發送消息須要咱們存儲與這個客戶端的聊天通道,也就是socket,那廣播消息呢?就須要咱們把這些管道都給存起來,一條管道來了消息,把消息廣播
出去bash
好了,思路有了,咱們來想一下有哪些問題,首先從聊天室的步驟提及,第一步是加入聊天室,咱們以前的代碼,accept以後就不會再調用這個方法
,也就是說,服務端不會接受新的客戶端connect,怎麼解決這個問題的呢,固然是監聽accept
(或者說不斷詢問)這裏,有返回值的時候就生成一個新的套接字,並把這個套接字存到咱們的用戶列表裏,也就是把全部通道都進行記錄
服務器
獲得與全部用戶的聯繫通道以後,咱們還要同時監聽全部的消息發送,而後進行咱們以前說的步驟,接受用戶消息,而後進行廣播多線程
下面是代碼部分,因爲要同時監聽accept與recv,咱們選擇select這個庫(select可真是個神奇的東西)app
import socket, select
#廣播函數
def broadcast_data (sock, message):
#不給發送消息者和accept廣播
for socket in CONNECTION_LIST:
if socket != server_socket and socket != sock :
try :
socket.send(message)
except :
socket.close()
CONNECTION_LIST.remove(socket)
if __name__ == "__main__":
#監聽列表,包括用戶列表和accept事件
CONNECTION_LIST = []
RECV_BUFFER = 4096 # Advisable to keep it as an exponent of 2
PORT = 5000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("0.0.0.0", PORT))
server_socket.listen(10)
#監聽accept的返回
CONNECTION_LIST.append(server_socket)
print "Chat server started on port " + str(PORT)
while 1:
#若是監聽列表裏有事件觸發,結果會返回到read_sockets裏,告知咱們有哪些消息來了
read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
#而後咱們就能夠進行以下處理
for sock in read_sockets:
#若是消息來自server_socket,說明有新鏈接到來
if sock == server_socket:
sockfd, addr = server_socket.accept()
CONNECTION_LIST.append(sockfd)
print "Client (%s, %s) connected" % addr
broadcast_data(sockfd, "[%s:%s] entered room\n" % addr)
else:
#來消息了
try:
data = sock.recv(RECV_BUFFER)
if data:
broadcast_data(sock, "\r" + '<' + str(sock.getpeername()) + '> ' + data)
#當client掉線時,recv會不斷受到空消息,因此關閉socket
if not data :
broadcast_data(sock, "\r" + '<' + str(sock.getpeername()) + '> ' + "下線了")
sock.close()
except:
broadcast_data(sock, "Client (%s, %s) is offline" % addr)
print "Client (%s, %s) is offline" % addr
sock.close()
CONNECTION_LIST.remove(sock)
continue
server_socket.close()
#client.py
import socket, select, string, sys,signal
def prompt() :
sys.stdout.write('<You> ')
sys.stdout.flush()
def sighandler(signum,frame):
sys.stdout.write("Shutdown Server......\n")
#向已經鏈接客戶端發送關係信息,並主動關閉socket
#關閉listen
sys.stdout.flush()
sys.exit()
if __name__ == "__main__":
signal.signal(signal.SIGINT,sighandler)
signal.signal(signal.SIGHUP,sighandler)
signal.signal(signal.SIGTERM, sighandler)
if(len(sys.argv) < 3) :
print('Usage : python telnet.py hostname port')
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try :
s.connect((host, port))
except :
print('Unable to connect')
sys.exit()
print('Connected to remote host. Start sending messages')
prompt()
while 1:
rlist = [sys.stdin,s]
read_list, write_list, error_list = select.select(rlist , [], [])
for sock in read_list:
if sock == s:
data = sock.recv(4096)
if not data :
print('\nDisconnected from chat server')
sys.exit()
else :
print (data.decode('utf-8'))
sys.stdin.flush()
prompt()
else :
msg = sys.stdin.readline()
s.send(msg.encode('utf-8'))
prompt()
複製代碼
參考文章:[Python Socket 編程——聊天室示例程序 By--hazir](https://www.cnblogs.com/hazir/p/python_chat_room.html)複製代碼