使用Socket套接字传输数据流程详解(面向过程)

本文详细阐述了使用socket进行数据传输的过程,包括创建socket、绑定端口、监听、客户端连接、send和recv操作,以及最后的socket关闭。以Unix系统为例,展示了如何在服务器和客户端间实现TCP通信。
摘要由CSDN通过智能技术生成

本篇文章目的是为了帮助理解使用socket传输数据时,过程是怎么样的,数据的走向是怎么样的,如有错误多多指正。

socket是计算机之间进行通信的一种约定方式,是应用层和输出层之间的一个抽象层。听过这个抽象层可以接受其他计算机的数据,也可以接收其他计算机的数据。如果这样比较难理解,可以把socket简单的理解成一个文本文件,一台计算机往socket上面写信息,另一台计算机从上面把信息取出来。

在unix系统中,要完成一次数据传递大概的流程如下图所示:

server/client代表服务端/客户端。内测的数字代表了工作的先后顺序,服务端和客户端都创建socket,然后服务端绑定端口并且进入监听状态,当收到客户端的connect信号,用accept接受连接请求。

连接成功后,就可以进行写send()读recv()操作。在传输完成后,关闭两端的socket。

Socket传递数据流程

按照上面的流程,第一步,我们先分别在两端创建socket套接字。(1)

使用socket() 函数;

int socket(int af, int type, int protocol);

af是本机IP地址类型,一般有PF_INET或者AF_INET(IPv4互联网协议族),还有PF_INET6(IPv6互联网协议族)等,但是一般用IPv4。

type有两种SOCK_STREAM 和SOCK_DGRAM分别对应tcp和udp协议,区别是用不用建立连接。

protocol是最终使用协议,默认填0就行。

因为socket函数返回值是int类型所以我们设置一个int值来存储。

客户端创建一个socket()如下:

int m_client = socket(AF_INET,SOCK_STREAM,0)

socket函数如果返回值<=0代表创建失败,一般不会出现这种情况。创建成功会返回一个大于零的值sfd,这个值和文件描述符fd很像,所以可以把socket比作一个文件。

之后我们可以通过这个sfd来操作socket。系统有一个数组存储了这个socket,fd就相当于这个数组一个索引,通过这个fd就可以找到并读取这个socket。

然后在客户端也创建一个如上的socket(m_server)后,进入下一步。(2)(3)

假设m_client是3,m_server是4; 

接下来是服务端的绑定和监听操作,其实这两部不一定在客户端的connect之后,只是如果没有这两步,客户端也即使发出connect信号也无法连接,所以我们按理想的流程进行。

在服务端中调用bind()和listen()函数。

int bind(int sock, struct sockaddr *addr, socklen_t addrlen);  

 bind()函数中的sock是我们之前创建服务端socket,假设是m_server的话,这里就填m_server。

第二个是sockaddr结构体,里面存放了协议,端口,IP地址等信息:

struct sockaddr {
  unsigned short sa_family;    // 协议族,与socket()函数的第一个参数相同,填AF_INET。
  unsigned char sa_data[14];    // 14字节的端口和地址。
};

所以我们创建一个sockaddr来储存这些信息,假设创建的sockaddr叫servaddr。信息手动赋值,如果麻烦可以用sockaddr_in结构体填写后转换成sockaddr。假设端口是5000,IP是htonl(INADDR_ANY),代表所有IP都能和它通讯,不会屏蔽。协议是AF_INEF。

简单来说,我们要把m_server这个socket与sveraddr里面的端口绑定,就是靠bind来完成的。好了,现在编号为4的socket绑定了端口5000。

第三个参数是sockaddr的大小,填sizeof(servaddr)就行。

int listen(int sock, int backlog); 

listen两个参数,第一个继续填m_server,也就是4。第二个填请求队列最大长度,一般填5,10,20都行。(如果需求小的话)

这里干了什么呢?首先listen函数中sock值告诉是m_server的socket,接着就可以知道之前bind的端口5000,所以开始监听5000端口。

第三步,客户端发送connect()请求,服务端accept()接受请求。(4)

首先看客户端,客户端调用connect()函数,

int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen); 

这个函数长得和之前的bind差不多,用到的参数意思是一样的,只是要填的不一样,里面实现的功能也不一样。

首先是sock填m_client,这里同样先要new一个sockaddr,端口继续是5000,IP是要连接的服务端的IP地址,这里假设服务端IP是255.255.255.255,协议是AF_INEF。然后继续取名叫servaddr。创建好后填写到第二个参数(填指针地址),第三个参数继续填sizeof(servaddr)。

这里就是往5000端口里发送连接信息。

接着到服务端,服务端调用accept()函数接受连接请求:

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); 

第一个参数填m_server,第二个参数我们要设置新的sockaddr取名caddr,这个sockaddr我们不需要往里面填东西。 

注意我们这里要创建一个新的int类型,取名就叫m_client(在服务端里,不会名字冲突),因为accept()会返回一个socket,这个socket其实就是客户端的socket m_client,所以我们在服务端里也直接取同名m_client。

从这里开始,客户端和服务端的联系就开始紧密起来了,从现在开始m_server这个socket就不要了,我们之后的读和写就已经同一在一个地方了,就是m_client,后续的操作也都是对m_client的操作。

第四步,发送信息send()和接受信息recv()。(5)(6)

ssize_t send(int fd, const void *buf, size_t nbytes);
ssize_t recv(int fd, const void *buf, size_t nbytes);

recv()和send()长得一样,只是一个是文件(也可以是数组,字符串等)读入缓冲区;一个是缓冲区读入文件。

缓冲区就是临时存放数据的地址。

假设我们设一个字符串sttr = “abcdefg”

现在要把这个字符串从客户端发送到服务端;

首先,在客户端中我们直接用send()函数直接发送,fd就填m_client,buf就填&sttr,nbtytes就填sttr的大小。这表面我们把sttr里面的数据写入m_client。

然后在服务端这边,我们先要创建一个接收信息的容器,就设char buffer[100];这个buffer用来装接收到的数据。

然后调用recv函数,第一个参数填m_client()。第二个参数填&buffer。第三个参数,因为大多数不知道发送过来多大的数据,所以我们需要先查一下获取数据大小。这里因为客户端和服务端都由我们操作,所以sttr的大小我是知道的。

这一步中recv函数把m_client里面的数据读取到了buffer里面。

到这里,就完成了一个简单的数据传输操作了。

最后一步就是把服务端和客户端的socket都关闭,调用close();(7)

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Python的套接字自动传输图片文件,你可以按照以下步骤进行操作: 1. 在发送端(客户端)将图片文件打开并读取为二进制数据。 2. 创建一个套接字并连接到接收端(服务器)的地址和端口。 3. 在发送端将图片数据通过套接字发送给接收端。 4. 在接收端接收数据并保存为图片文件。 以下是一个简单的示例代码,演示了如何使用socket套接字自动传输图片文件: **发送端(客户端)代码:** ```python import socket def send_image(image_path, host, port): # 打开并读取图片文件 with open(image_path, 'rb') as file: image_data = file.read() # 创建套接字并连接到服务器 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((host, port)) # 发送图片数据 client_socket.sendall(image_data) # 关闭套接字 client_socket.close() # 示例使用 image_path = 'image.jpg' # 图片文件路径 host = '服务器地址' port = 12345 # 服务器端口 send_image(image_path, host, port) ``` **接收端(服务器)代码:** ```python import socket def receive_image(save_path, host, port): # 创建套接字并绑定到指定地址和端口 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((host, port)) # 监听连接 server_socket.listen(1) print(f"等待来自客户端的连接...") # 接受连接并接收图片数据 client_socket, address = server_socket.accept() print(f"连接来自:{address}") # 接收图片数据 image_data = client_socket.recv(1024) # 保存图片文件 with open(save_path, 'wb') as file: file.write(image_data) # 关闭套接字 client_socket.close() server_socket.close() print("图片接收完成!") # 示例使用 save_path = 'received_image.jpg' # 接收到的图片保存路径 host = '0.0.0.0' # 服务器地址(监听所有可用的网络接口) port = 12345 # 服务器端口 receive_image(save_path, host, port) ``` 在上述代码中,你需要将`image.jpg`替换为要发送的图片文件路径。在接收端,你需要指定一个保存接收到的图片的路径`received_image.jpg`。此外,你还需要指定发送端和接收端所在的服务器地址和端口。 请注意,这只是一个简单的示例,仅用于演示基本的图片文件传输。在实际应用中,你可能需要添加错误处理、文件大小处理等逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值