【计算机网络】TCP&UDP通信实验

既然TCP/UDP通信协议如此重要,我们应该如何将其简单模拟出来呢?下面是利用Python里的socket数据包的方法简单模拟实现TCP和UDP通信。实验内容来自《计算机网络-自顶向下方法第七版》。

UDP通信实验

实验目标:使用Python的socket包实现UDP通信

实现效果:

客户端:

服务器端:

UDP通信原理

如果我们想要用socket包实现UDP通信实验,那我们就需要首先知道socket的作用。socket也称为套接字,使用它可以将分组从应用程序向下层结构发送。下面就是socket和应用层、运输层的关系,socket就好比房子的们,应用程序就是房子,我们的报文就是从房子向外面(运输层)运输的货物。

明白了socket的作用后,我们需要看看如何用Python来设计一个UDP通信程序。按照通信的原则,一个有效的通信应用体系应该包括信息的发送程序和信息的接收程序。所以我们也应该设计一个客户程序和服务器程序。

客户端

在设计客户端程序之前我们首先需要导入socket工具包。

import socket

当我们导入工具包后,我们就需要去确定我们客户端发送的消息应该发送到哪里,也就是说我们需要确定服务器的IP,但是这还不过,我们将报文发送到主机后我们还需要确定我们发送到报文由主机上的哪个进程接收,也就是说需要发送到哪个主机号。为此我们定义两个变量分别存储服务器IP和端口号,而我们客户端由哪个端口发送就由操作系统来帮助我们指定即可。

serverIP = '192.168.xx.xx'
severPort = 10000

这里我选择的服务器端口号是10000,但是我们进行通信实验之前,我们首先需要确保我们使用的端口没有被其他进程占用。如果想检查端口是否被占用,可以输入netstat -ano指令查看所有的端口的状况,如果想明确到某一个端口,可以直接输入netstat -ano|findstr “端口号”来确定该端口是否被占用。

紧接着就是创建一个套接字UdpClientSocket了,创建套接字使用到的是socket包里面的socket函数,它返回的对象就是我们需要的套接字,这里我们需要传递两个参数socket.AF_INETsocket.SOCK_DGRAM,它们分别用于确定使用IPV4和使用UDP协议。这里我们需要将客户端的数据发送给服务器,为此我设计一个message变量来接收用户输入。

UdpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print('**********客户端************')
message = input('请输入要发送的句子:')

紧接着就需要将我们得到的用户输入message发送出去,具体是调用创建的套接字变量里面的sendto函数,并且将我们的数据传递过去,但是我们需要注意我们需要将数据由字符串转换为字节后再传递出去,所以就需要调用encode()函数,最后再传递一个元组,这个元组的第一个元素是服务器IP,第二个参数就是服务器调用的端口号。

UdpClientSocket.sendto(message.encode(), (serverIP, severPort))

接着我们需要设计一个反馈给客户端,证明服务器接收到了数据,为此我们调用套接字对象里的recvfrom函数,它会返回一个元组,这个元组第一个元素是服务器返回的信息,第二个是服务器的套接字地址(IP和端口号) ,它的参数2048表示取缓存长度为2048的数据。最后我们在客户端将服务器返回的数据再次从字节转换为字符串后输出,并且也输出服务器的IP和端口号。最后再将套接字关闭即可。

modifiedMessage, serverAddress = UdpClientSocket.recvfrom(2048)
print(modifiedMessage.decode())
print('服务器的IP地址为:',serverAddress[0], '服务器端口号为:', serverAddress[1])
UdpClientSocket.close()

服务器端

设计完客户端后,接下来就需要设计出服务器端的设置了,首先还是照旧导入数据包socket里的全部函数,然后照旧指出服务器端口号和创建套接字。

from socket import *
serverPort = 10000
serverSocket = socket(AF_INET, SOCK_DGRAM)

 接下来就需要使用下面的代码将服务器的10000端口号与服务器绑定,绑定方式是将本机IP和端口号绑定,本地IP可以不写(用' '代替),但是端口号需要写出来,这样客户端发送到数据就可以通过这个套接字发送到服务器了。

serverSocket.bind(('', serverPort))

最后就设计一个死循环,这个死循环一直在待定,等待我们发送信息,一旦接收到信息后,我们这里设计的处理是将这些信息转化为字节方式后发送一条反馈信息给客户端。

while 1:
    message, clientAddress = serverSocket.recvfrom(2048)
    modifiedMessage = '您发的'+message.decode()+'已经接收到了'
    serverSocket.sendto(modifiedMessage.encode(), clientAddress)

TCP通信实验

TCP通信原理

TCP通信和UDP通信不一样,TCP通信更加安全和保障,自然而然它的实现方法就和之前相比有很大区别。TCP通信之前通信的双方客户端和服务器端之间需要建立一个TCP连接,报文就通过这个连接在双方进行通信,与之前不同的是,报文通信不需要附上目的地的IP和端口号,它只需要通过开启的TCP连接通道通信即可。

在通信前,客户端会开启一个套接字进行对外通信,与UDP实验不同的是TCP通信时服务器端会开启两个套接字,一个用于响应客户端初始发过来的连接请求(套接字A),一个用于在主机和客户端之间传输信息(套接字B)。当客户端初次与服务器接触发起TCP连接时,它会去指定服务器的第一个套接字并与其进行接触,接触完后服务器会生成一个新的套接字B与客户端进行TCP连接,然后再真正传递信息。而这些都是发生在三次握手期间的动作。

客户端

TCP通信客户端的设计和UDP虽然不同,不过它们有很多相似的地方。首先照旧是创建两个存放服务器的IP地址和端口号的变量;再创建一个套接字对象,它的创建方法和UDP类似,不过它的第二个参数是SOCK_STREAM

ServerIP = '192.168.xx.xx'
ServerPort = 10000
ClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

上面这个套接字是客户端往外通信的套接字,但是TCP通信是需要双方三次握手构建一个TCP连接,这点与UDP不同,所以下面我们还需要设置一条和服务器之间的TCP通信通道:

ClientSocket.connect((ServerIP, ServerPort))

创建完这条通道,我们需要将我们想发的信息从键盘读取并且以字节的形式发送出去,这里我们使用的是send函数,不同于UDP的sendto,因为这里以及建立了TCP连接,传输时可以不附加IP和端口号。我们还在客户端配置好接收来自服务器的反馈信息,使用recv函数。这里不同的是我们之前使用recvfrom函数,因为recvfrom可以用于UDP和TCP通信,而recv常用于TCP通信。将返回的信息输出后,最后我们再将套接字关闭即可。

ClientSocket.connect((ServerIP, ServerPort))
print('*'*20+'客户端'+'*'*20)
Content = input('请输入内容:')
ClientSocket.send(Content.encode())
Rec = ClientSocket.recvfrom(2048)
print(Rec[0].decode())
ClientSocket.close()

服务器端

对于服务器端,TCP通信首先也需要创建一个套接字,这个套接字是用于和客户端初始接触的套接字,即前面提到的套接字A。这里我们还是指定用服务器的10000端口并且指定其用于服务器的套接字。

import socket
ServerPort = 10000
ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ServerSocket.bind(('', ServerPort))

不过不同的是我们需要将这个套接字指定为等待状态

ServerSocket.listen(1)

等弄完这些后我们就可以着手准备写通信时用到的套接字B了,我们首先设定套接字A一直处于等待创建套接字B的状态,即在此之后写一个while循环:一旦客户端发送信息,我们调用的是套接字A对象的accept方法,这个方法会返回一个套接字B对象和一个记载客户端数据的(IP和端口)元组。然后就调用新套接字B的方法recv来接收客户端传递过来的数据,最后再转换为字节的形式发送(send)回去即可。

while 1:
    Connectsocket, Info = ServerSocket.accept()
    RecMessage = Connectsocket.recv(2048)
    print('接收到'+RecMessage.decode())
    SendMessage = '您发送的'.encode()+RecMessage.decode().encode()+'已接受到'.encode()
    Connectsocket.send(SendMessage)
    Connectsocket.close()

实现效果:

客户端:

服务器端: 


参考资料:

《计算机网络-自顶向下方法第七版》

猜你喜欢

转载自blog.csdn.net/m0_61151031/article/details/128780038