概念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)复制代码