Python聊天室
一、套接字
套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象。它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。
套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳。许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。
三种最流行的套接字类型是:stream,datagram和raw。stream和datagram套接字可以直接与TCP协议进行接口,而raw套接字则接口到IP协议。但套接字并不限于TCP/IP。
二、套接字模块
套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问。使用该模块可以实现客户机和服务器套接字。要在python 中建立具有TCP和流套接字的简单服务器,需要使用socket模块。利用该模块包含的函数和类定义,可生成通过网络通信的程序。
服务器端:
step-1:
创建socket对象。调用socket构造函数。
socket=socket.socket(familly,type)
family的值可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(对于IPV4协议的TCP和 UDP),至于type参数,SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw套接字)。
step-2:
将socket绑定(指派)到指定地址上。
socket.bind(address)
address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。
step-3:
绑定后,必须准备好套接字,以便接受连接请求。
socket.listen(backlog)
backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。
step-4:
服务器套接字通过socket的accept方法等待客户请求一个连接。
connection,address=socket.accept()
调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有俩个元素的元组,形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客户通信;第二个元素(address)是客户的internet地址。
step-5:
处理阶段,服务器和客户通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接受端。以后调用recv时,多余的数据会从缓冲区删除。
step-6:
传输结束,服务器调用socket的close方法以关闭连接。
客户端:
step-1:
创建一个socket以连接服务器。
socket=socket.socket(family,type)
step-2:
使用socket的connect方法连接服务。
socket.connect((host,port))
step-3:
客户和服务器通过send和recv方法通信。
step-4:
结束后,客户通过调用socket的close方法来关闭连接。
server.py
if __name__ == '__main__':
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("XXX.XXX.XXX.X", XXXX))
sock.listen(5)
connection,address = sock.accept()
data = connection.recv(1024)
print data
if data == '1\'m on your own side.':
connection.send('welcome!')
else:
connection.send('gun!')
connection.close()
client.py
if __name__ == '__main__':
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("XXX.XXX.XXX.X", XXXX))
key=raw_input("join us or not? y/n. ")
if key is "y":
sock.send('1\'m on your own side.')
if key is "n":
sock.send('fuck you all!')
print sock.recv(1024)
sock.close()
这是一个简单网络编程。
在终端运行server.py,然后运行clien.py,会在终端打印“join us or not? y/n."。如果客户端输入"y",则服务器端会收到"1'm on your own side."。如果客户端输入"n",则服务器端会收到"fuck you all!",然后服务器端会回敬一句"gun!"。
serverplus.py
import socket,select,thread;
host=socket.gethostname()
port=5963
addr=(host,port)
inputs=[]
fd_name={}
def main():
print 'runing'
ss=socket.socket()
ss.bind(addr)
ss.listen(5)
inputs.append(ss)
while True:
r,w,e=select.select(inputs,[],[])
for temp in r:
if temp is ss:
client,add=ss.accept()
print 'welcome %s %s' % (client,add)
wel='''welcome into the talking room . please decide your name.....'''
try:
client.send(wel)
name=client.recv(1024)
inputs.append(client)
fd_name[client]=name
for client in fd_name:
fd_name.append(fd_name[client])
nameList="Some people in talking room, these are %s" % (fd_name)
client.send(nameList)
except Exception,e:
print e
else:
disconnect=False
try:
data= temp.recv(1024)
data=fd_name[temp]+' say : '+data
except socket.error:
data=fd_name[temp]+' leave the room'
disconnect=True
if disconnect:
inputs.remove(temp)
print data
for other in inputs:
if other!=ss and other!=temp:
try:
other.send(data)
except Exception,e:
print e
del fd_name[temp]
else:
print data
for other in inputs:
if other!=ss and other!=temp:
try:
other.send(data)
except Exception,e:
print e
if __name__=='__main__':
main()
clientplus.py
import socket,select,threading,sys;
host=socket.gethostname()
addr=(host,5963)
def lis(s):
my=[s]
while True:
r,w,e=select.select(my,[],[])
if s in r:
try:
print s.recv(1024)
except socket.error:
print 'socket is error'
exit()
def talk(s):
while True:
try:
info=raw_input()
except Exception,e:
print 'can\'t input'
exit()
try:
s.send(info)
except Exception,e:
print e
exit()
def main():
ss=socket.socket()
ss.connect(addr)
t=threading.Thread(target=lis,args=(ss,))
t.start()
t1=threading.Thread(target=talk,args=(ss,))
t1.start()
if __name__=='__main__':
main()
这是一个终端聊天室,加入了多线程运行和异常处理。
chatroom.py
import wx,socket,select,thread,Queue,sys
class chatdlg(wx.Dialog):
#initUI
def __init__(self):
wx.Dialog.__init__(self,None,-1,"chat room",size=(400,400))
wx.StaticText(self,-1,"IP",pos=(10,14))
self.IPText = wx.TextCtrl(self,-1,"",pos=(30,10),size=(104,25))
wx.StaticText(self,-1,"Port",pos=(144,14)) ;
self.PortText = wx.TextCtrl(self,-1,"",pos=(180,10),size=(46,25))
wx.StaticText(self,-1,"Nickname",pos=(236,14))
self.NicknameText = wx.TextCtrl(self,-1,"*Anonym",pos=(304,10),size=(80,25))
self.cButton = wx.Button(self,-1,"Client",pos=(10,45),size=(185,50))
self.Bind(wx.EVT_BUTTON,self.OnClientClick,self.cButton)
self.sButton = wx.Button(self,-1,"Server",pos=(200,45),size=(185,50))
self.Bind(wx.EVT_BUTTON,self.OnSeverClick,self.sButton)
self.DisplayText = wx.TextCtrl(self,-1,"",pos=(10,104),size=(373,198),style=wx.TE_MULTILINE)
self.InputText = wx.TextCtrl(self,-1,"",pos=(10,312),size=(263,50),style=wx.TE_MULTILINE)
self.sendButton = wx.Button(self,-1,"Send",pos=(283,312),size=(100,50))
self.Bind(wx.EVT_BUTTON,self.OnSendClick,self.sendButton)
self.sendButton.SetDefault()
#SendButoon
def OnSendClick(self,event):
#self.sendButton.SetLabel("Clicked")
self.send_data = self.InputText.GetValue()
self.nick_name = self.NicknameText.GetValue()
try:
self.client.send(self.nick_name+" said: "+self.send_data+"\n")
self.DisplayText.AppendText(self.nick_name+" said: "+self.send_data+"\n")
self.InputText.SetValue("")
except socket.error,e:
print "could not connect to chat server @%s:%d\n" % (self.host,self.port)
return
#ServerButoon
def OnSeverClick(self,event):
self.socketmode=1
thread.start_new_thread(self.SocketProc_server,())
#ClientButton
def OnClientClick(self,event):
self.socketmode=0
#self.cButton.SetLabel("connected")
thread.start_new_thread(self.SocketProc_client,())
#Server
def SocketProc_server(self):
# Sockets to which we expect to write
outputs = [ ]
# Outgoing message queues (socket:Queue)
message_queues = {}
self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.port = int(self.PortText.GetValue())
self.host = ""
print "waiting for connection @%s:%d\n" % (self.host,self.port)
self.server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.server.bind((self.host,self.port))
self.server.listen(10)
self.DisplayText.AppendText("waiting for connection @%s:%d\n" % (self.host,self.port))
# Sockets from which we expect to read
inputs = [ self.server ]
while inputs:
# Wait for at least one of the sockets to be ready for processing
print >>sys.stderr,"waiting for the next event\n"
readable,writable,exceptional = select.select(inputs,outputs,inputs)
# Handle inputs
for s in readable:
if s is self.server:
# A "readable" server socket is ready to accept a connection
connection,client_address = s.accept()
print >>sys.stderr,"new connection from",client_address
self.DisplayText.AppendText("new connection from @%s:%s\n" % client_address)
connection.setblocking(False)
inputs.append(connection)
# Give the connection a queue for data we want to send
message_queues[connection] = Queue.Queue()
else:
data = s.recv(1024)
if data:
# A readable client socket has data
print >>sys.stderr,"@%s:%s" % (s.getpeername(),data)
self.DisplayText.AppendText("@%s:%s" % (s.getpeername(),data))
for c in inputs:
if c is self.server:
print >>sys.stderr,"from server"
elif c is not s:
print >>sys.stderr,"send_data [%s] to %s" % (data,s.getpeername())
message_queues[c].put(data)
if c not in outputs:
outputs.append(c)
else:
# Interpret empty result as closed connection
print >>sys.stderr,"closing",client_address,"after reading no data"
self.DisplayText.AppendText("closing @%s:%s after reading no data\n\n" % client_address)
# Stop listening for input on the connection
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
# Remove message queue
del message_queues[s]
# Handle outputs
for s in writable:
try:
next_msg = message_queues[s].get_nowait()
except Queue.Empty:
# No messages waiting so stop checking for writability.
print >>sys.stderr,"output queue for",s.getpeername(),"is empty"
outputs.remove(s)
else:
print >>sys.stderr,'sending "%s" to %s' % (next_msg,s.getpeername())
s.send(next_msg)
# Handle "exceptional conditions"
for s in exceptional:
print >>sys.stderr,"handling exceptional condition for",s.getpeername()
self.DisplayText.AppendText("handling exceptional condition for",s.getpeername())
# Stop listening for input on the connection
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
# Remove message queue
del message_queues[s]
#Client
def SocketProc_client(self):
# Sockets to which we expect to write
outputs = [ ]
# Outgoing message queues (socket:Queue)
message_queues = {}
self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.host = str(self.IPText.GetValue())
self.port = int(self.PortText.GetValue())
print "Connecting to chat server@%s:%d\n" % (self.host,self.port)
try:
self.client.connect((self.host,self.port))
print "connected to chat server @%s:%d\n" % (self.host,self.port)
except socket.error,e:
print "Could not connect to chat server @%s:%d\n" % (self.host,self.port)
return
inputs = [ self.client ]
message_queues[self.client] = Queue.Queue()
while inputs:
# Wait for at least one of the sockets to be ready for processing
print >>sys.stderr,"\nwaiting for the next event"
readable,writable,exceptional = select.select(inputs,outputs,inputs)
# Handle inputs
for s in readable:
data = s.recv(1024)
if data:
# A readable client socket has data
print >>sys.stderr,'received "%s" from %s' % (data,s.getpeername())
self.DisplayText.AppendText(data)
else:
# Interpret empty result as closed connection
print >>sys.stderr,"closing",client_address,"after reading no data"
self.DisplayText.AppendText("closing @%s:%s after reading no data\n\n" % client_address)
# Stop listening for input on the connection
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
# Remove message queue
del message_queues[s]
# Handle outputs
for s in writable:
try:
next_msg = message_queues[s].get_nowait()
except Queue.Empty:
# No messages waiting so stop checking for writability.
print >>sys.stderr,"output queue for",s.getpeername(),"is empty"
outputs.remove(s)
else:
print >>sys.stderr,'sending "%s" to %s' % (next_msg,s.getpeername())
s.send(next_msg)
# Handle "exceptional conditions"
for s in exceptional:
print >>sys.stderr,"handling exceptional condition for",s.getpeername()
self.DisplayText.AppendText("handling exceptional condition for",s.getpeername())
# Stop listening for input on the connection
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
# Remove message queue
del message_queues[s]
def SocketProc_process(self):
pass
#recv all recv_data
#broadcast msg
if __name__ == "__main__":
app = wx.PySimpleApp()
app.MainLoop()
dialog = chatdlg()
result = dialog.ShowModal()
if result == wx.ID_OK:
print "OK"
else:
print "Cancel"
dialog.Destroy()
这是一个图形聊天室,加入了图形界面。
//如果有用,那么本文是lancer写的
//如果没用,那么我也不知道是谁写的