使用socket包来简单编程实现客户端与服务器端的简单通信。

客户端:

客户端主要就是负责向服务器端发送请求,等待服务器端响应之后接收服务器发送的信息。

使用socket库,创建一个socket(套接字),抽象理解一下就是一个连接。

创建一个套接字对象,传入AF_INET表示使用IPV4的IP地址,SOCK_STREAM表示传输数据是流数据(因为这个是TCP编程的,安全性较高,保证数据必须完整,所以采用流数据传输方式,具体的传输方式是因为有个缓冲区,详细的理解流数据传输可以自己搜)。这样就创建了一个基于TCP协议的socket。

然后开始连接服务器,使用socket的connect方法,需要传入一个元组,元组里面有俩参数,一个是目标服务器的IP地址(这里我因为要发送的服务器的IP地址是自己的电脑本机,就传入的是自己电脑的名字,或者是127.0.0.1也表示本机IP地址),另一个数服务器的端口号(端口号指定服务器提供什么样的服务,1024以下的端口都是常规端口,给固定的程序应用,3389是远程桌面的固定端口)

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 这里的hostname是自己电脑名称,为什么也可以传入到connect里面还不清楚。
# 正常的传入connect的应该是个IP地址,比如127.0.0.1就代表本机的IP地址。
hostname = socket.gethostname()
#端口号可以根据服务器随便设置
s.connect((hostname,9999))

客户端连接之后就可以接收到服务器端发送的信息,这里使用recv()方法,需要传入一个参数,表示一次最多能接收到多少字节的数据。

这里还需要知道在网络编程里服务器和浏览器接收发送的数据都是字节bytes类型的,在python语言中前面加个b就表示是字节类型的数据。所以从服务器接收到的数据要转成python语言的utf-8的格式:在python里面bytes和str的互相转换就是str.encode('utf-8')和bytes.decode('utf-8')。这里得到的数据需要经过解码成utf-8的格式,然后就可以打印出来。

#连接建立之后应该可以接收到服务器端发送的信息了
data1 = s.recv(1024)
# 接收到的是字节类型的数据,需要解码成utf-8的python数据。
data1_utf = data1.decode("utf-8")
print("接收到服务器端的信息"+data1_utf)

这一段就是实现服务器端和客户端的简单通信:客户端首先发送一条Hello的信息(因为服务器和浏览器接收还是发送都是字节类型的,所以这里也发送的是字节类型的数据),客户端发送信息之后,服务器会再发送一条信息,跟上面一样解码然后打印出来,这样就是客户端与服务器端的一次简单通信。最后记得关闭连接。

s.send(b'Hello')
data2 = s.recv(1024)
data2_utf = data2.decode("utf-8")
#必须要解码成utf-8的格式,这样python才能使用,不然会报错
print("第二次接收到服务器端的信息"+data2_utf)

s.close()

服务器端:

新建一个套接字对象socket:这里用到socket的两个方法bind()和lsiten()。

bind()是服务器端的方法,同样需要传入一个元组,IP地址和端口号,表示我这个服务器的IP地址和开放的端口号;listen()是负责监听的,表示最多能连接几个客户端。这样定义好socket之后就会开始监听客户端发送的连接请求。

import socket
import threading

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#获取自己电脑的名字,我的电脑的名字就是LAPTOP-AIS8I7KF,是个字符串
#为什么是需要这个主机名还是不知道,本来应该用的是一个IP地址,这里我的理解就是获取自己电脑的IP地址。
hostname = socket.gethostname()
#print(hostname)

# 负责监听,需要传入两个参数,一个是IP地址,一个是端口号,是一个元组
s.bind((hostname,9999))

# 负责监听端口,传入的参数表示允许连接的最大数量
s.listen(3)
print("等待连接中......")

这里必须得写一个while循环,因为要不断接收新的连接,然后创建新的线程来处理这个连接。

accept()方法也是服务器端的方法,注意这里没有传入参数,这个方法一般会放在listen()监听之后,accept()会默认阻塞进程,直到有一个客户端进行连接。socket调用这个方法就会返回一个新的socket,这个socket是一个新的,具体是怎么创建的不知道,只知道这个新的socket负责实现客户端与服务器端的通信)和本机的IP地址和端口号

python tcp 包头 python tcp编程_客户端


接着新建一个线程(这里补充一下线程的用法,新建的线程需要传入两个参数,一个是这个线程需要执行的函数名,另一个是这个函数需要传入的数据),新建的线程负责运行这个函数,根据函数和accept返回的新的socket和addr(还不知道有啥用),来实现与客户端之间的通信。

#必须写这个while循环,因为要不断监听socket连接,然后将新的连接来创建一个新的线程处理。
while True:
# accept()这个方法不会接收参数,但是会返回两个值,一个是socket连接,一个是当前这个socket套接字的地址。
# 这里返回的是一个新的套接字socket,既不是客户端的,也不是服务器端的socket(具体怎么用不知道)
# 将接收的这两个参数传入函数,并且通过新建的线程执行。
    sock,addr = s.accept()
#这里再补充一下线程的知识,创建一个线程需要传入两个参数:
# 一个是这个线程需要执行的函数,另一个是这个函数需要传入的参数。
    t = threading.Thread(target=fun_tcp,args=(sock,addr))
    t.start()

客户端与服务器之间的通信函数:使用新建传入的socket,首先会向客户端发送一个Welcome。之后while一个循环负责接收客户端的信息,如果客户端的信息是Hello,就会发送victory,然后不会接收信息,结束连接,如果收到的信息不是Hello,就会发送“match wrong",同样结束通信。

#这个就是对来的连接进行处理,必须要写在while循环前面。
# 这里传入的socket是一个新的套接字连接,用于发送服务器的信息和接收客户端的信息,就是两边都通信。
#既可以接收信息又可以发送信息。
def fun_tcp(sock,addr):
#这个就是发送信息
    sock.send(b"Welcome")

#除了发送信息,还能接收客户端的信息
    while True:
        data = sock.recv(1024)
        if data == b"Hello":
            sock.send(b"victory")
            print("通信成功了")
            break
        else:
            sock.send(b"match wrong")
            print("通信成功了,但是客户端发送的信息不匹配")
            break
    sock.close()
    print("通信关闭")
# 这里我建立连接之后,会先向客户端发送一条Welcome信息,然后由客户端发送一条信息,
# 要是客户端发送的信息是Hello(字节类型的),服务器端就会发送victory,不然就会发送match wrong,然后就会关闭通信。

这样就实现了python网络编程客户端和服务器端之间的简单通信。

完整代码

服务器端

import socket
import threading

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#获取自己电脑的名字,我的电脑的名字就是LAPTOP-AIS8I7KF,是个字符串
#为什么是需要这个主机名还是不知道,本来应该用的是一个IP地址,这里我的理解就是获取自己电脑的IP地址。
hostname = socket.gethostname()
#print(hostname)

# 负责监听,需要传入两个参数,一个是IP地址,一个是端口号,是一个元组
s.bind((hostname,9999))

# 负责监听端口,传入的参数表示允许连接的最大数量
s.listen(3)
print("等待连接中......")

#这个就是对来的连接进行处理,必须要写在while循环前面。
# 这里传入的socket是一个新的套接字连接,用于发送服务器的信息和接收客户端的信息,就是两边都通信。
#既可以接收信息又可以发送信息。
def fun_tcp(sock,addr):
#这个就是发送信息
    sock.send(b"Welcome")

#除了发送信息,还能接收客户端的信息
    while True:
        data = sock.recv(1024)
        if data == b"Hello":
            sock.send(b"victory")
            print("通信成功了")
            break
        else:
            sock.send(b"match wrong")
            print("通信成功了,但是客户端发送的信息不匹配")
            break
    sock.close()
    print("通信关闭")
# 这里我建立连接之后,会先向客户端发送一条Welcome信息,然后由客户端发送一条信息,
# 要是客户端发送的信息是Hello(字节类型的),服务器端就会发送victory,不然就会发送match wrong,然后就会关闭通信。


#必须写这个while循环,因为要不断监听socket连接,然后将新的连接来创建一个新的线程处理。
while True:
# accept()这个方法不会接收参数,但是会返回两个值,一个是socket连接,一个是当前这个socket套接字的地址。
# 这里返回的是一个新的套接字socket,既不是客户端的,也不是服务器端的socket(具体怎么用不知道)
# 将接收的这两个参数传入函数,并且通过新建的线程执行。
    sock,addr = s.accept()
#这里再补充一下线程的知识,创建一个线程需要传入两个参数:
# 一个是这个线程需要执行的函数,另一个是这个函数需要传入的参数。
    t = threading.Thread(target=fun_tcp,args=(sock,addr))
    t.start()

客户端

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 这样应该就是创立连接了
hostname = socket.gethostname()
s.connect((hostname,9999))

#连接建立之后应该可以接收到服务器端发送的信息了
data1 = s.recv(1024)
# 接收到的是字节类型的数据,需要解码成utf-8的python数据。
data1_utf = data1.decode("utf-8")
print("接收到服务器端的信息"+data1_utf)

s.send(b'Hello')
data2 = s.recv(1024)
data2_utf = data2.decode("utf-8")
#必须要解码成utf-8的格式,这样python才能使用,不然会报错
print("第二次接收到服务器端的信息"+data2_utf)

s.close()

运行截图

首先运行服务器端,此时开始监听,等待客户端的连接

python tcp 包头 python tcp编程_网络_02

 运行客户端,然后就会收到服务器端发送的Welcome信息,之后又会向服务器端发送Hello信息,得到一个victory信息。

python tcp 包头 python tcp编程_客户端_03

 此时服务器端已经连接上客户端发送的信息,已经完成和客户端通信,并且关闭通信,但此时中这个服务器端的进程还未关闭,因为外面的while还没有停止,应该是一种进程阻塞的状态,等待着客户端来进行连接。

python tcp 包头 python tcp编程_服务器_04