在Linux操作系统中,网络编程是非常重要的一部分。而网络编程中,数据的传输和接收是必不可少的。在Linux编程中,接收数据时通常会使用到 recvfrom 函数。本文将详细讲解 Linux 编程中 recvfrom 函数的定义、用法以及注意事项。
一、recvfrom 函数的定义
recvfrom 函数是 Linux 中的系统调用函数,主要用于接收数据。该函数的定义如下:
“`c
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
“`
其中,各个参数的含义如下:
– sockfd:表示接收数据的套接字描述符;
– buf:表示接收数据的缓冲区;
– len:表示接收数据的缓冲区的长度;
– flags:表示接收数据时的额外选项;
– src_addr:源地址信息;
– addrlen:源地址信息的长度。
该函数的返回值为 ssize_t,表示成功接收到的数据长度。如果返回-1,则表示出现错误。此时可以通过 perror 函数打印错误信息,以便进行调试。
二、recvfrom 函数的用法
在使用 recvfrom 函数时,我们需要先创建一个 socket 套接字,并将其绑定到一个 IP 地址和端口号上。接下来,我们就可以使用 recvfrom 函数来接收数据了。具体的代码如下所示:
“`c
#include
#include
#include
#include
#include
#include
#include
#define PORT 8888
#define MAXLINE 1024
int mn(int argc, char *argv[])
{
int sockfd;
char buffer[MAXLINE];
struct sockaddr_in servaddr, cliaddr;
// 创建 socket 套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror(“socket creation fled”);
exit(EXIT_FLURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// 初始化服务器地址结构
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// 绑定服务器地址结构到 socket 套接字上
if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
perror(“bind fled”);
exit(EXIT_FLURE);
}
printf(“Server listening on port %d\n”, PORT);
// 接收数据
while (1) {
socklen_t len = sizeof(cliaddr);
ssize_t n = recvfrom(sockfd, buffer, MAXLINE, 0, (struct sockaddr *)&cliaddr, &len);
if (n == -1) {
perror(“recvfrom error”);
exit(EXIT_FLURE);
}
buffer[n] = ‘\0’;
printf(“Received message from client: %s\n”, buffer);
// 向客户端发送数据
int ret = sendto(sockfd, (const char *)buffer, strlen(buffer), 0, (const struct sockaddr *)&cliaddr, len);
if (ret == -1) {
perror(“sendto error”);
exit(EXIT_FLURE);
}
printf(“Message sent to client: %s\n”, buffer);
}
close(sockfd);
return 0;
}
“`
该程序首先创建了一个 UDP 套接字,并将其绑定到 localhost:8888 这个地址上。然后,通过一个 while 循环持续监听是否有数据发送过来。如果接收到了数据,就将其打印出来,并向客户端发送一条相同的消息。
三、recvfrom 函数的注意事项
在使用 recvfrom 函数时,需要注意以下几点:
1. 如果缓冲区大小小于接收到的数据大小,那么函数会将缓冲区填满,并且截断那些超过缓冲区的部分;
2. 如果设置了 MSG_PEEK 标志,那么 recvfrom 函数只是读取数据,并不会将数据从输入队列中移除;
3. 如果设置了 MSG_DONTWT 标志,那么 recvfrom 函数将不会阻塞,即使没有数据可读,它也会立即返回;
4. 当通过 sendto 函数向远程主机发送数据时,需要注意参数的正确性,否则会出现数据发送失败的情况。
相关问题拓展阅读:
- linux 下用socket 文件传输问题(UDP)
linux 下用socket 文件传输问题(UDP)
你传输文本的时候用的什么函数阿?send/recv?还是sendto/recvfrom?或者直接read/write?
文件不是一样的?只不过需要自己拟定一个协议,比如先发送文件大小,然后把文件打开了往里放不就好了,没有难度吧
要下班了,时间急,不写代码了先给你一个思路
实现最简单的udp socket 模型,实现发送一个字符串。
实现一个简单的打开文件,读取文件的例子,如用fgets(),类似的函数有很多,然后再把读取的文件内容忘另一个文件里写(相关函数fopen(),write(),read())。
把上面两个函数结合到一起,在客户端实现打开要传送的文件,按一定的大小读取,读取后调用sendto()发送到服务器端。在服务器端创建一个文件,然后调用recvfrom()接受客户端发送过来的数据,向来是创建的那个文件中写。
下面是改好的udp发送文件的例子。
服务器端程序的编译
gcc -o file_server file_server
客户端程序的编译
gcc -o file_client file_client.c
服务器程序和客户端程应当分别运行在2台计算机上.
服务器端程序的运行,在一个计算机的终端执行
./file_server
客户端程序的运行,在另一个计算机的终端中执行
./file_client 运行服务器程序的计算机的IP地址
根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上
在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序,
服务器端程序的运行,在一个终端执行
./file_server
客户端程序的运行,在另一个终端中执行
./file_client 127.0.0.1
说明: 任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1
//////////////////////////////////////////////////////////////////////////////////////
// file_server.c 文件传输顺序服务器示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是服务器的代码
#include // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr, pcliaddr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的据报套接字(UDPt,用server_socket代表服务器socket
// 创建数据报套接字(UDP)
int server_socket = socket(PF_INET,SOCK_DGRAM,0);
if( server_socket FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
//int fp = open(file_name, O_RDON);
//if( fp 0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf(“file_block_length = %d\n”,file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0) // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
if (argc != 2)
{
printf(“Usage: ./%s ServerIPAddress\n”,argv);
exit(1);
}
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_DGRAM,0);
if( client_socket BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
socklen_t n = sizeof(server_addr) ;
sendto(client_socket,buffer,BUFFER_SIZE,0,(struct sockaddr*)&server_addr,n);
// int fp = open(file_name, O_WRON|O_CREAT);
// if( fp // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
int server_socket = socket(PF_INET,SOCK_STREAM,0);
if( server_socket FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
//int fp = open(file_name, O_RDON);
//if( fp 0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf(“file_block_length = %d\n”,file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0) // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
if (argc != 2)
{
printf(“Usage: ./%s ServerIPAddress\n”,argv);
exit(1);
}
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_STREAM,0);
if( client_socket BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
send(client_socket,buffer,BUFFER_SIZE,0);
// int fp = open(file_name, O_WRON|O_CREAT);
// if( fp
FILE * fp = fopen(file_name,”w”);
if(NULL == fp )
{
printf(“File:\t%s Can Not Open To Write\n”, file_name);
exit(1);
}
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
int length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
{
if(length
{
printf(“Recieve Data From Server %s Failed!\n”, argv);
break;
}
//int write_length = write(fp, buffer,length);
int write_length = fwrite(buffer,sizeof(char),length,fp);
if (write_length
{
printf(“File:\t%s Write Failed\n”, file_name);
break;
}
bzero(buffer,BUFFER_SIZE);
}
printf(“Recieve File:\t %s From Server Finished\n”,file_name, argv);
close(fp);
//关闭socket
close(client_socket);
return 0;
}