【发布时间】:2026-01-16 14:40:01
【问题描述】:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
static char *host = "irc.libera.chat";
static char *port = "6667";
static char *chan = "#libera";
static char *nick = "nick";
static char *pass = NULL;
static int sock = 0;
void
message(char *fmt, ...) {
va_list ap;
/* determine size */
va_start(ap, fmt);
int n = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed", stderr);
exit(EXIT_FAILURE);
}
size_t size = n + 1;
/* construct */
char *msg = malloc(size);
if (msg == NULL) {
perror("malloc() failed");
exit(EXIT_FAILURE);
}
va_start(ap, fmt);
n = vsnprintf(msg, size, fmt, ap);
va_end(ap);
if (n < 0) {
fputs("vsnprintf() failed\n", stderr);
free(msg);
exit(EXIT_FAILURE);
}
/* send */
ssize_t nsent = send(sock, msg, size, 0);
free(msg);
if (nsent == -1) {
perror("send() failed");
exit(EXIT_FAILURE);
} else if ((size_t)nsent != size) {
fprintf(stderr,
"send() failed: expected to send %lu bytes, sent %ld instead\n",
size, nsent);
exit(EXIT_FAILURE);
}
}
int
main(void) {
/* initialize connection */
struct addrinfo hints = {
.ai_flags = 0,
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_addrlen = 0,
.ai_addr = NULL,
.ai_canonname = NULL,
.ai_next = NULL
};
struct addrinfo *res;
int ret = getaddrinfo(host, port, &hints, &res);
if (ret != 0) {
fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(ret));
return EXIT_FAILURE;
}
struct addrinfo *rp;
for (rp = res; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock == -1) {
perror("socket() failed");
continue;
}
if (connect(sock, rp->ai_addr, rp->ai_addrlen) == -1) {
perror("connect() failed");
close(sock);
continue;
}
break;
}
freeaddrinfo(res);
if (rp == NULL) {
fprintf(stderr, "could not connect to %s:%s\n", host, port);
return EXIT_FAILURE;
}
/* log in */
if (pass)
message("PASS %s\n", pass);
message("NICK %s\n", nick);
message("USER %s - - :%s\n", nick, nick);
/* join channel */
if (chan != NULL)
message("JOIN %s\n", chan);
/* print response */
char buffer[4096];
ssize_t nbyte;
loop:
nbyte = recv(sock, buffer, 4095, 0);
if (nbyte < 0) {
fputs("recv() failed", stderr);
return 1;
} else if (nbyte == 0) {
fputs("recv() failed: connection closed prematurely", stderr);
return 1;
}
buffer[nbyte] = '\0';
printf("%s", buffer);
goto loop;
/* unreachable */
}
输出
:calcium.libera.chat NOTICE * :*** Checking Ident
:calcium.libera.chat NOTICE * :*** Looking up your hostname...
:calcium.libera.chat NOTICE * :*** Couldn't look up your hostname
:calcium.libera.chat NOTICE * :*** No Ident response
ERROR :Closing Link: 127.0.0.1 (Connection timed out)
recv() failed: connection closed prematurely
- 为什么我没有收到正确的响应?
其他irc客户端进一步输出
:calcium.libera.chat 001 nick :Welcome to the Libera.Chat Internet Relay Chat Network nick
...
问题可能出在错误处理中吗?
比如根据send(2)
成功时,这些调用会返回发送的字节数。出错时返回 -1,并设置 errno 以指示错误。
所以
} else if ((size_t)nsent != size) {
fprintf(stderr,
"send() failed: expected to send %lu bytes, sent %ld instead\n",
size, nsent);
exit(EXIT_FAILURE);
}
似乎是多余的,以及它的recv 对应物。
我处理vsnprintf 和malloc 是否正确?
【问题讨论】:
-
每个帖子一个问题。
-
Checking Ident ... Looking up your hostname ... Couldn't look up your hostname ... No Ident response- 您的代码中没有 IDENT 服务器。大多数 IRC 服务器会在端口 113 上连接回客户端的 IP 并查询其身份以证明客户端就是它声称的身份。因此,您需要在代码中实现一个 IDENT 服务器,或者至少让一个 IDENT 服务器与您的客户端并行运行。 -
@RemyLebeau 但这不是问题,因为其他 irc 客户端在输出其他有用的东西之前也会给出相同的四行。
-
另外,不,您没有正确处理
send()。如果它返回 > 0,但小于请求的字节数,则必须再次调用send()以完成剩余未发送字节的发送。返回值与请求的大小不同不是错误。唯一的错误条件是返回值 -1。您需要循环调用send(),直到发送完所有数据。 -
loop: ... goto loop;?哇。好几年没见过像 THAT 这样的代码了 ;)