int sock_client_connect(
const char *server_name,
int port)
{
struct addrinfo *res, *t;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM
};
char *service;
int n;
int sockfd = -1;
if (asprintf(&service, "%d", port) < 0) {
fprintf(stderr, "asprintf failed\n");
return -1;
}
n = getaddrinfo(server_name, service, &hints, &res);
if (n < 0) {
fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), server_name, port);
free(service);
return -1;
}
for (t = res; t; t = t->ai_next) {
sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
if (sockfd >= 0) {
if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
break;
close(sockfd);
sockfd = -1;
}
}
freeaddrinfo(res);
free(service);
if (sockfd < 0) {
fprintf(stderr, "couldn't connect to %s:%d\n", server_name, port);
return -1;
}
return sockfd;
}
这段代码是一个名为 `sock_client_connect` 的函数,用于在客户端建立与服务器的连接。
函数接受两个参数:`server_name` 表示服务器的名称或IP地址,`port` 表示要连接的端口号。
函数首先定义了一个 `addrinfo` 结构体指针数组 `res` 和 `t`,用于存储服务器的地址信息。然后定义了一个 `hints` 结构体,指定了地址族为 `AF_UNSPEC`(任意地址族)和套接字类型为流式套接字(SOCK_STREAM)。
接下来,函数使用 `asprintf` 函数将端口号转换为字符串,并将其存储在 `service` 变量中。如果转换失败,则打印错误消息并返回 -1。
然后,函数调用 `getaddrinfo` 函数,传入服务器名称、服务名称、地址信息提示和地址信息指针数组,以获取服务器的地址信息。如果获取失败,则打印错误消息,释放 `service` 变量并返回 -1。
接下来,函数遍历地址信息链表,依次创建套接字并尝试连接服务器。如果连接成功,则跳出循环;否则关闭套接字并继续尝试下一个地址。最后,释放地址信息链表和 `service` 变量。
如果最终无法连接到服务器,则打印错误消息并返回 -1。
如果连接成功,则返回套接字文件描述符。
注意:这段代码使用了 `getaddrinfo`、`asprintf`、`socket`、`connect` 和 `freeaddrinfo` 等函数,需要在代码中包含相应的头文件(例如 ``、``、`` 等)。
以下是原始代码:
```c
#include
#include
#include
#include
#include
int main() {
const char *server_name = "localhost";
int port = 8080;
int sockfd = sock_client_connect(server_name, port);
if (sockfd == -1) {
perror("sock_client_connect");
exit(EXIT_FAILURE);
}
else {
puts("Connected");
// Do something with the connected socket
shutdown(sockfd, SHUT_WR);
while (true) { // Just keep it open for now
usleep(100000); // 100ms
}
}
return 0;
}
int sock_client_connect(
const char *server_name,
int port) {
struct addrinfo *res, *t;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM
};
char *service;
int n;
int sockfd = -1;
if (asprintf(&service, "%d", port) < 0) {
fprintf(stderr, "asprintf failed\n");
return -1;
}
n = getaddrinfo(server_name, service, &hints, &res);
if (n < 0) {
fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), server_name, port);
free(service);
return -1;
}
for (t = res; t; t = t->ai_next) {
sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
if (sockfd >= 0) {
if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
break;
close(sockfd);
sockfd = -1;
}
}
freeaddrinfo(res);
free(service);
if (sockfd < 0) {
fprintf(stderr, "couldn't connect to %s:%d\n", server_name, port);
return -1;
}
return sockfd;
}
```
该程序的主要功能是使用`getaddrinfo`函数获取服务器名称和端口号,然后使用`socket`和`connect`函数创建并连接到套接字。如果无法建立连接,它将打印错误消息并返回-1。否则,它将输出“已连接”并关闭套接字。
这是一个用C语言编写的函数,其目的是在客户端建立一个与指定服务器和端口的连接。这个函数使用了getaddrinfo函数来获取地址信息,然后用socket和connect函数来建立连接。
以下是函数的详细步骤:
定义一个addrinfo结构体的指针变量res和一个临时变量t。
定义一个addrinfo结构体hints,其中指定了地址族为AF_UNSPEC(可以是IPv4或IPv6),以及套接字类型为SOCK_STREAM(TCP流套接字)。
使用asprintf函数将端口号转换为字符串,如果失败则打印错误信息并返回-1。
调用getaddrinfo函数,将服务器名、端口号和hints作为参数,以获取地址信息。如果失败,则打印错误信息并释放之前分配的内存,然后返回-1。
遍历所有的地址信息。对于每一个地址,创建一个套接字,然后尝试连接到该地址。如果连接成功,则跳出循环并继续执行。如果连接失败,则关闭该套接字并继续尝试下一个地址。
如果所有的地址都尝试过但连接仍然失败,则释放地址信息和端口号字符串的内存,然后打印错误信息并返回-1。
如果连接成功,则返回套接字的文件描述符。
这个函数的功能相当于在socket编程中手动进行getaddrinfo、socket和connect等操作。通过使用这个函数,可以让代码更加简洁和易于管理。
这段代码是一个用于连接到服务器的客户端函数,它接受两个参数:服务器名称和服务端口。函数的返回值为客户端套接字文件描述符,如果连接失败则返回 -1。下面是对这段代码的中文分析:
1. 定义一个结构体指针 res,用于存储服务器地址信息;定义一个结构体指针 t,用于遍历地址信息;定义一个名为 hints 的结构体,用于存储地址解析时的家族、协议和套接字类型等信息。
2. 定义一个字符指针 service,用于存储端口号的字符串表示;定义一个整数变量 n,用于存储地址解析的结果;定义一个整数变量 sockfd,用于存储客户端套接字文件描述符。
3. 使用 asprintf 函数将端口号格式化为字符串,并将其存储在 service 指针指向的内存中。如果格式化失败,函数将返回 -1,并输出错误信息。
4. 使用 getaddrinfo 函数根据服务器名称和服务端口获取地址信息。如果获取地址信息失败,函数将返回 -1,并输出错误信息。同时释放 service 指针指向的内存。
5. 使用一个 for 循环遍历地址信息。在循环中,为每个地址创建一个套接字,并尝试连接到服务器。如果连接成功,跳出循环;如果连接失败,关闭套接字并重置 sockfd 为 -1。
6. 释放地址信息,释放 service 指针指向的内存。如果 sockfd 为 -1,说明连接失败,输出错误信息。
7. 返回客户端套接字文件描述符。如果连接成功,返回值为套接字文件描述符;如果连接失败,返回值为 -1。