使用AF_INET实现点对点的通信示例

本文介绍了一个简单的UDP客户端与服务器之间的通信流程。客户端通过指定的端口向服务器发送消息,而服务器则绑定到该端口并在接收到消息后打印出来。文中提供了客户端和服务器端的C语言代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:Younger Liu,本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

1.    客户端(发送方)

操作流如下:

(1) 使用AF_INET协议簇,创建基于数据报的socket对象;

(2) 发送方不会在程序中显式的绑定自己的IP信息,但系统会帮助完成这一动作,并指定随机的端口信息,所以接收端显示的端口信息并不会每次都一样;

(3) 发送端向接收端的7838端口发送数据,然后退出

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
     struct sockaddr_in s_addr;
     int sock, addr_len, len;
     char buff[128];
     if(-1 == (sock = socket(AF_INET, SOCK_DGRAM, 0)))
     {
         printf("socket");
         exit(errno);
     }
     else
         printf("create socket.\n");

     s_addr.sin_family = AF_INET;
     s_addr.sin_port = htons(7838);

    if(argv[1])
	{
     	s_addr.sin_addr.s_addr = inet_addr(argv[1]);
    }
    else
    {
     	printf("input server ip!\n");
        exit(0);
    }
    addr_len = sizeof(s_addr);

    strcpy(buff,"hello i am here");
    len = sendto(sock, buff, strlen(buff),
     				0, (struct sockaddr *)&s_addr, addr_len);
    if(len < 0)
	{
		printf("\n send error.\n");
	    return 3;
	}
	printf("send success.\n\r");
	
	return 0;
}


2.    服务器端(接收方)

操作流如下:

(1) 使用AF_INET协议簇,创建基于数据报的socket对象;

(2) 绑定自己的IP和端口,此端口也是发送方程序向接收端发起连接时指定的接收端端口;

(3) 接收端阻塞式接收发送端数据;

(4) 如果接收到数据,读取数据并处理。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
	struct sockaddr_in s_addr, c_addr;
    int sock, len;
    socklen_t addr_len;
    char buff[128];
    if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
    	printf("socket");
    	exit(errno);
    }
    else
    	printf("create socket.\n\r");
    
    memset(&s_addr, 0, sizeof(struct sockaddr_in));
    
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(7838);
    s_addr.sin_addr.s_addr = INADDR_ANY;
    
    if((bind(sock,(struct sockaddr *)&s_addr, sizeof(s_addr))) == -1)
    {
        printf("bind");
        exit(errno);
    }
    else
    	printf("bind address to socket.\n\r");
    
    addr_len=sizeof(c_addr);
    while(1) {
    	len = recvfrom(sock, buff, sizeof(buff) - 1,
    			0, (struct sockaddr *)&c_addr, &addr_len);   
        if(len<0)
        {
            printf("recvfrom");
            exit(errno);
        }
    
        buff[len]='\0';
        printf("recive come from %s:%d message:%s\n\r",
        	inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port), buff);
    }
    
    return 0;
}
作者:Younger Liu, 本作品采用 知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议 进行许可。

<think>首先,用户的问题是:“请问socket(AF_INET SOCK_DGRAM 0) 的作用和使用方法”。这是一个关于网络编程的查询,具体是关于使用socket API创建UDP套接字。 根据系统级指令,我需要: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - 确保LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答实可靠。 参考提供的引用: - 引用[1]:解释了SocketAF_UNIX、AF_INET、SOCK_STREAM和SOCK_DGRAM。 - 引用[2]:描述了使用SOCK_DGRAM创建UDP套接字。 - 引用[3]:给出了Python中使用UDP套接字的代码示例。 - 引用[4]:解释了UDP套接字的特点,如不可靠、开销小。 用户意图是了解socket(AF_INET, SOCK_DGRAM, 0)的作用和使用方法。这似乎是C语言中的调用,因为0通常是协议参数,表示默认协议。 关键点: - `AF_INET`:表示地址家族,用于IPv4地址。 - `SOCK_DGRAM`:表示套接字类型,用于数据报,即UDP。 - `0`:协议参数,通常表示使用默认协议,对于UDP是IPPROTO_UDP。 在socket函数中,函数签名通常是:`int socket(int domain, int type, int protocol);` - domain: AF_INET(IPv4) - type: SOCK_DGRAM(数据报) - protocol: 0(表示自动选择协议,对于SOCK_DGRAM,默认是UDP) 所以,`socket(AF_INET, SOCK_DGRAM, 0)`的作用是创建一个UDP套接字。 使用方法: 1. 创建套接字:调用socket函数。 2. 绑定地址(可选):对于服务器端,通常绑定到特定IP和端口。 3. 发送和接收数据:使用sendto和recvfrom函数。 4. 关闭套接字。 在回答中,我需要结构化: - 解释作用。 - 描述使用方法。 - 提供简单示例(由于用户问题似乎是C语言相关,我可以给一个C代码片段)。 - 确保使用中文。 - 生成相关问题。 最后,生成相关问题,基于主题。 回答结构: 1. **引入**:简要介绍socket函数和UDP。 2. **作用**:解释`socket(AF_INET, SOCK_DGRAM, 0)`的具体作用。 3. **使用方法**:分步说明如何使用,包括创建、绑定、发送、接收和关闭。 4. **代码示例**:提供一个简单的C代码示例。 5. **注意事项**:提到UDP的特性,如不可靠性。 6. **相关问题**:生成几个相关问题。 引用标识:在引用内容末尾添加[^1]、[^2]等。参考引用[2]和[4],因为它们直接相关。 例如: - 根据引用[2],UDP套接字可以使用socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)创建,但0是等价的。 - 引用[4]解释了UDP的特点。 确保LaTeX:如果涉及数学,但这里可能不涉及数学表达式,除非有公式。用户问题中没有数学,所以可能不需要LaTeX,但指令说如果有变量等使用$...$。这里可能没有数学内容。 生成相关问题: - 例如:如何绑定UDP套接字?UDP与TCP的区别?如何处理UDP数据报丢失? 完整回答: - 开头:直接回答问题。 - 主体:逐步解释。 - 结尾:生成相关问题。</think>### socket(AF_INET, SOCK_DGRAM, 0) 的作用和使用方法 `socket(AF_INET, SOCK_DGRAM, 0)` 是网络编程中用于创建 UDP 套接字的函数调用。UDP(User Datagram Protocol)是一种无连接的传输协议,适用于对实时性要求高但允许少量数据丢失的场景,如视频流、DNS 查询等。下面我将逐步解释其作用和使用方法,确保内容实可靠,基于标准网络编程实践。 #### 1. **作用** - **核心功能**:创建一个基于 IPv4 的 UDP 套接字。套接字是网络通信的端点,用于发送和接收数据报。 - `AF_INET`:指定地址家族为 IPv4,表示使用 32 位 IP 地址(如 `192.168.1.1`)[^1]。 - `SOCK_DGRAM`:指定套接字类型为数据报(datagram),即 UDP 模式。这种模式不支持连接建立,数据以独立报文形式传输,开销小但不可靠(可能丢失或乱序)[^4]。 - `0`:协议参数,表示使用默认协议。对于 `SOCK_DGRAM`,系统会自动选择 UDP 协议(等价于 `IPPROTO_UDP`)。因此,`socket(AF_INET, SOCK_DGRAM, 0)` 等同于 `socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)`[^2]。 - **关键特性**: - **无连接性**:无需建立连接,直接发送数据。 - **低开销**:传输效率高,适合小数据包。 - **不可靠性**:不保证数据顺序、完整性和可达性,需应用层处理错误[^4]。 #### 2. **使用方法** 使用 `socket(AF_INET, SOCK_DGRAM, 0)` 创建 UDP 套接字后,需配合其他函数完成通信。以下是标准步骤(以 C 语言为例),适用于服务器端和客户端。 ##### 步骤 1: 创建套接字 - 调用 `socket()` 函数创建套接字句柄。 - 检查返回值:成功返回非负文件描述符(fd),失败返回 -1(需错误处理)。 ```c #include <sys/socket.h> #include <netinet/in.h> int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } ``` ##### 步骤 2: 绑定地址(可选,通常用于服务器) - 服务器端需绑定到特定 IP 和端口,以监听数据。 - 使用 `struct sockaddr_in` 设置地址结构。 - 调用 `bind()` 函数绑定套接字。 ```c struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; // IPv4 server_addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有本地 IP server_addr.sin_port = htons(8080); // 端口号(主机字节序转网络字节序) if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); close(sockfd); exit(EXIT_FAILURE); } ``` ##### 步骤 3: 发送和接收数据 - **发送数据**:使用 `sendto()` 函数,需指定目标地址。 - **接收数据**:使用 `recvfrom()` 函数,获取数据和发送者地址。 - 示例:服务器接收数据并回显(客户端类似,但无需绑定)。 ```c char buffer[1024]; struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); // 接收数据 ssize_t recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &addr_len); if (recv_len < 0) { perror("recvfrom failed"); } // 发送响应(例如回显数据) ssize_t send_len = sendto(sockfd, buffer, recv_len, 0, (struct sockaddr*)&client_addr, addr_len); if (send_len < 0) { perror("sendto failed"); } ``` ##### 步骤 4: 关闭套接字 - 通信结束后,关闭套接字释放资源。 ```c close(sockfd); ``` #### 3. **注意事项** - **错误处理**:UDP 无连接,需处理丢包和乱序(如添加序列号或使用超时重传)。 - **跨平台兼容性**:在 Windows 中,需包含 `winsock2.h` 并初始化 Winsock 库。 - **性能优化**:对于高负载场景,可设置套接字选项(如 `SO_RCVBUF` 增大缓冲区)。 - **安全提示**:UDP 易受攻击(如 DDoS),建议添加数据验证(如校验和)。 #### 4. **简单示例:UDP 客户端** 以下是一个完整 C 语言客户端示例,发送消息到服务器。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket failed"); return 1; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); // 服务器端口 inet_pton(AF_INET, "192.168.1.102", &server_addr.sin_addr); // 服务器 IP char *msg = "Hello, UDP Server!"; ssize_t sent = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (sent < 0) { perror("sendto failed"); } close(sockfd); return 0; } ``` #### 引用说明 - 创建 UDP 套接字时,`SOCK_DGRAM` 直接对应 UDP 协议,确保数据报传输[^2]。 - UDP 的无连接特性使其适用于低延迟应用,但需注意可靠性问题[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YoungerChina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值