目录
1.创建套接字 socket()
函数原型
参数
返回值
2.bind()
一、网络编程中的 bind() 函数
主要用途
函数原型
返回值
3.recvfrom()
一、函数原型
二、返回值
三、常见错误
4.sendto()
一、函数原型
二、参数说明
三、返回值
四、使用注意事项
socket()
函数是网络编程中的一个基本且关键的函数,它用于创建一个新的套接字(socket)。套接字是网络通信中的端点,它允许不同主机上的进程之间进行数据的发送和接收。socket()
函数在多种编程语言中都有对应的实现,但最基础和广泛使用的是在C语言中的定义,它也被许多其他语言通过标准库或扩展库间接支持。
在C语言中,socket()
函数的原型定义在
头文件中(在Windows上可能是
并且需要初始化Winsock DLL):
#include
#include
#include
int socket(int domain, int type, int protocol);
domain
:指定了协议族(protocol family)。最常用的协议族是 AF_INET
,它代表IPv4协议;另一个是 AF_INET6
,它代表IPv6协议。type
:指定了套接字类型。最常用的类型是 SOCK_STREAM
,它表示面向连接的TCP协议;另一个是 SOCK_DGRAM
,它表示无连接的UDP协议。protocol
:指定了具体的协议。大多数情况下,这个参数可以设置为0,让系统自动选择该类型套接字和协议族对应的默认协议。socket()
函数返回一个非负整数,它是套接字的描述符(socket descriptor)。这个描述符在后续的套接字操作中(如绑定、监听、接受连接、发送和接收数据)将被使用。socket()
函数返回-1,并设置全局变量 errno
以指示错误原因。bind()
函数在不同的编程环境和上下文中具有不同的作用,但主要可以分为两大类:网络编程中的 bind()
函数和编程语言(如C++、JavaScript)中的 bind()
函数。
bind()
函数在网络编程中,bind()
函数主要用于将一个套接字(socket)与一个地址(包括IP地址和端口号)绑定在一起。这是服务器端编程中的一个关键步骤,通常在创建套接字后使用。
bind()
函数通过给一个未命名套接口分配一个本地名字(即主机地址/端口号)来为套接口建立本地捆绑。在UNIX/Linux环境下,bind()
函数的原型如下:
#include
#include
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd
:标识要绑定的套接字的文件描述符。addr
:指向包含地址信息的结构体的指针,通常使用 struct sockaddr_in
表示IPv4地址,或 struct sockaddr_in6
表示IPv6地址。addrlen
:地址结构体的大小,可以用 sizeof
操作符获得。bind()
函数返回0。errno
以指示错误原因。recvfrom()
函数是网络编程中的一个重要函数,特别是在使用UDP协议进行通信时。它用于从套接字接收数据,并可以返回发送数据的源地址。以下是recvfrom()
函数的详细解析:
在C语言中,recvfrom()
函数的原型通常如下(以UNIX/Linux系统为例):
recvfrom() 函数是网络编程中的一个重要函数,特别是在使用UDP协议进行通信时。它用于从套接字接收数据,并可以返回发送数据的源地址。以下是recvfrom()函数的详细解析:
一、函数原型
在C语言中,recvfrom()函数的原型通常如下(以UNIX/Linux系统为例):
其中,参数的含义如下:
sockfd
:已打开并绑定的套接字的文件描述符。buf
:指向缓冲区的指针,用于存储接收到的数据。len
:缓冲区的大小(以字节为单位),表示函数最多可以接收的数据量。flags
:控制接收行为的标志位,如MSG_DONTWAIT
(非阻塞模式)、MSG_WAITALL
(阻塞模式,直到接收到指定大小的数据)等。src_addr
:一个指向sockaddr
结构体的指针,用于存储发送方的地址信息。如果不需要获取发送方的地址,可以设置为NULL。addrlen
:一个指向整型的指针,用于指定src_addr
结构体的大小。在调用recvfrom()
之前,应该将其设置为src_addr
结构体的大小,在调用之后,它将被设置为新接收到的地址的实际大小。recvfrom()
返回接收到的字节数。errno
来指示错误的原因。使用recvfrom()
时,需要处理可能出现的各种错误情况,例如:
recvfrom()
可能会返回EAGAIN
或EWOULDBLOCK
错误。EBADF
(无效的套接字描述符)、EFAULT
(参数中有一指针指向无法存取的内存空间)、ENOTSOCK
(参数s为一文件描述词,非socket)等。sendto
函数是网络编程中用于向指定的目的地址发送数据报的函数,特别是在使用UDP协议时非常常见。以下是对 sendto
函数的详细解析:
在C语言中,sendto
函数的原型通常如下(以UNIX/Linux系统为例):
#include
#include
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
sockfd
:已打开的套接字文件描述符,该套接字必须已经通过 socket()
函数创建,并且对于UDP协议来说,不需要通过 connect()
函数建立连接。buf
:指向要发送数据的缓冲区的指针。len
:要发送的数据的长度(以字节为单位)。flags
:发送选项的标志位,通常为0,表示使用默认行为。但也可以设置其他标志位,如 MSG_DONTROUTE
(绕过本地路由表)、MSG_DONTWAIT
(非阻塞模式)等。dest_addr
:指向目的地址的指针,该地址必须是一个 sockaddr
结构体(或其特定类型的变体,如 sockaddr_in
用于IPv4),包含了目标主机的IP地址和端口号。addrlen
:目的地址的长度,对于 sockaddr_in
结构体,其长度通常为 sizeof(struct sockaddr_in)
。sendto
返回发送的字节数。errno
来指示错误的原因。sendto
之前,必须确保 sockfd
是一个有效的、已经打开的套接字文件描述符。dest_addr
指向的地址是正确的,包括IP地址和端口号。sendto
后,应该检查其返回值以确保数据成功发送。flags
参数为 MSG_DONTWAIT
来使 sendto
调用在非阻塞模式下工作。sendto
函数不会关心目标地址是否可达或是否存在,只是简单地将数据报发送到网络上。UDP(User Datagram Protocol,用户数据报协议)是一种无连接的传输层协议,它基于IP协议,提供了一种将数据包发送到网络上的方式。UDP协议的特点主要包括以下几个方面:
综上所述,UDP协议以其无连接性、高效性、快速性等特点在特定应用场景中发挥着重要作用。然而,由于其不可靠性,UDP并不适用于所有类型的网络应用,特别是在对数据可靠性要求较高的场景中。
#include
#include
#include
#include
#include
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
// 创建 socket 文件描述符
if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 绑定 socket 到端口 8080
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 设置 socket 选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
while (true) {
// 接收数据
int len = recvfrom(server_fd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&address, (socklen_t*)&addrlen);
buffer[len] = '\0';
std::cout << "Message from client: " << buffer << std::endl;
// 发送响应(如果需要)
// sendto(server_fd, (const char *)buffer, strlen(buffer), MSG_CONFIRM, (const struct sockaddr *)&address, addrlen);
}
return 0;
}