在网络编程中的一个基本组件就是套接字(socket)。套接字基本上是两个端点的程序之间的“信息通道”。程序可能分布在不同的计算机上,通过套接字互相发送信息。套接字包括两个:服务器套接字和客户机套接字。在创建一个服务器套接字后,让它等待连接。这样它就在某个网络地址处(ip地址和端口的组合)监听,直到有客户端套接字连接。连接完成后,二者就可以进行交互了。

socket套接字
一个套接字就是socket模块中socket类的一个实例。它的实例化需要3个参数:
第1个参数是地址族,默认是socket.AF_INET(指定使用IPv4协议)
第2个参数是流,默认是socket.SOCK_STREAM(指定面向流的TCP协议),或者数据报socket.SOCK_DGRAM套接字。
第3个参数是使用的协议,默认是0

import socket
# s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 这里我们全部使用默认值就行了
s=socket.socket()

服务器套接字使用bind方法后,再调用listen方法去监听某个特定的地址。

s.bind(('127.0.0.1',9999))#绑定地址和端口
s.listen(5)#服务器开始监听客户端连接,允许排队等待的连接数目是5,一般都设5

端口是自己设的,ip我用的是本机的ip地址,当然如果服务器程序在其他主机上,就要换成其他的ip。端口号低于1024一般都被限制使用,它们被用于标准服务,例如端口80用于web服务。

服务器套接字开始监听后,它就静静的等待客户端的连接了。这个步骤使用accept方法完成,这个方法会阻塞直到客户端的连接。该方法返回一个格式为(client,address)的元组,client是客户端套接字,address是格式为(host,port)的元组。服务器在处理完与该客户端的连接后,再次调用accept方法开始等待下个连接,通常这个过程用一个无限循环实现。

while True:
    #接受一个客户端连接
    sock,addr=s.accept()#addr是个元组('127.0.0.1',端口)
    #接下来可以创建新线程来处理当前客户端的连接

现在我们来看客户端怎么连接服务器,客户端套接字使用connect方法连接服务器,在connect方法中使用的地址必须和服务器在bind方法中绑定的地址相同。

import socket
c=socket.socket()#创建客户端套接字
c.connect(('127.0.0.1',9999))#连接服务器

套接字有两个方法:send和recv,分别用来发送和接收数据。send方法以字符串作为参数,recv用一个最大字节数来作为参数,如果不确定,使用1024比较好。

c.send('hello,I am xxx!')
c.recv(1024)

基础内容介绍完后,我们现在来看个完整的例子,客户端连接服务器,客户端向服务器发送一组名字xxx,然后服务器回复hello,xxx!。

#服务器
import socket
import threading
#处理客户端请求
def tcplink(sock,addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send('welcome!')
    while True:
        data=sock.recv(1024)
        if data=='exit' or not data:
            break;
        sock.send('hello %s' % data)
    sock.close()
    print('Connection from %s:%s closed' % addr)

s=socket.socket()
s.bind(('127.0.0.1',9999))#绑定地址和端口
s.listen(5)
print('serve is waiting connect.....')
while True:
    sock,addr=s.accept()
    #创建新线程来处理每个客户端连接
    #target=tcplink代表新线程要运行哪个函数
    #args=(sock,addr)代表向这个方法传的参数
    t=threading.Thread(target=tcplink,args=(sock,addr))
    #启动这个线程
    t.start()
#客户端
import socket
import threading
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立连接
s.connect(('127.0.0.1',9999))
data=s.recv(1024)
print(data)
for i in ['zhangkang','jack','tom']:
    s.send(i)
    data=s.recv(1024)
    print(data)
s.send('exit')
s.close()

Python中的socket网络编程(TCP/IP,UDP)讲解

TCP建立的是可靠的连接,而UDP是无连接,不可靠的。使用UDP的时候,只需要知道目标主机的ip和端口就行了,然后直接发送,能不能到达就不一定了。
和TCP类型,服务器套接字需要先实例,然后绑定地址。

#这里第二个参数选择数据报
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind(('127.0.0.1', 9999))

但是服务器不需要调用listen()方法,而是直接接收客户端的数据

while True:
    # 接收数据:
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s' % addr)
    s.sendto('Hello, %s!' % data, addr)

recvfrom()方法返回数据和客户端的地址与端口,这样,服务器收到数据后,直接调用sendto()就可以把数据用UDP发给客户端。

客户端使用UDP时,首先仍然创建基于UDP的Socket,然后,不需要调用connect(),直接通过sendto()给服务器发数据:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in ['zhangkang', 'jack', 'tom']:
    # 发送数据:
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收数据:
    print s.recv(1024)
s.close()

从服务器接收数据仍然调用recv()方法。

简单的聊天室程序

这里我写了一个简易的类似聊天室的程序,没有使用图形界面,全部消息都显示在控制台。

#服务器
# -*- encoding: utf-8 -*-
import socket
import threading

def tcplink(sock,addr):
    print('[%s:%s] is online...' % addr)
    while True:
        try:
            data=sock.recv(1024)
        except:
            socket_set.remove(sock)
            print('[%s:%s] is down!' % addr)
            break
        if data=='exit' or not data:
            socket_set.remove(sock)
            sock.close()
            print('[%s:%s] is down!' % addr)
            break
        else:
            list1=[]
            for i in socket_set:
                if i!=sock:
                    list1.append(i)
            for i in list1:
                i.send(data)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socket_set=set()#用来保存每个socket对象
s.bind(('127.0.0.1',9999))#绑定地址和端口
s.listen(5)
print('serve is waiting connect.....')
while True:
    #接受一个客户端连接
    sock,addr=s.accept()#addr是个元组('127.0.0.1',端口)
    socket_set.add(sock)#把socket对象添加到集合中
    #创建新线程来处理TCP连接
    t=threading.Thread(target=tcplink,args=(sock,addr))
    t.start()
#客户端
# -*- encoding: utf-8 -*-
import socket
import threading

name=raw_input('input you name:')
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立连接
s.connect(('127.0.0.1',9999))
def rec_message():
    while True:
        try:
            data=s.recv(1024)
            print('\r['+data+']')
        except:
            break

t=threading.Thread(target=rec_message)
t.start()
while True:
    st=raw_input()
    if st=='exit':
        s.send(st)
        s.close()
        break
    s.send(name+":"+st)

Python中的socket网络编程(TCP/IP,UDP)讲解

客户端逐个下线
Python中的socket网络编程(TCP/IP,UDP)讲解

分类:

技术点:

相关文章: