[socket] client function - sock_client_connect

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` 等函数,需要在代码中包含相应的头文件(例如 `<sys/types.h>`、`<sys/socket.h>`、`<netdb.h>` 等)。
以下是原始代码:
```c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>

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。

Guess you like

Origin blog.csdn.net/eidolon_foot/article/details/132623247