用C语言写socket ipv6客户端非阻塞方式收发信息代码
时间: 2024-01-29 10:04:40 浏览: 272
以下是一个使用C语言编写的IPv6客户端非阻塞方式收发信息的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#define SERVER_ADDR "2001:db8::1" // 服务器地址
#define SERVER_PORT "12345" // 服务器端口号
#define BUF_SIZE 1024 // 缓冲区大小
int main(int argc, char *argv[]) {
int sockfd, ret;
struct addrinfo hints, *result, *rp;
char buf[BUF_SIZE];
ssize_t nread, nwrite;
fd_set rset, wset;
// 设置hints结构体
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6; // IPv6地址族
hints.ai_socktype = SOCK_STREAM; // TCP协议
// 获取服务器地址信息
ret = getaddrinfo(SERVER_ADDR, SERVER_PORT, &hints, &result);
if (ret != 0) {
perror("getaddrinfo");
exit(EXIT_FAILURE);
}
// 遍历地址信息并进行连接
for (rp = result; rp != NULL; rp = rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sockfd == -1) {
continue; // 创建socket失败,尝试下一个地址
}
// 设置socket为非阻塞模式
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
ret = connect(sockfd, rp->ai_addr, rp->ai_addrlen);
if (ret == 0) {
break; // 连接成功
} else if (errno == EINPROGRESS) {
// 连接正在进行中,等待连接完成
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
ret = select(sockfd + 1, &rset, &wset, NULL, NULL);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
fprintf(stderr, "select timeout\n");
exit(EXIT_FAILURE);
} else {
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
int err;
socklen_t len = sizeof(err);
ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len);
if (ret == -1) {
perror("getsockopt");
exit(EXIT_FAILURE);
}
if (err == 0) {
break; // 连接成功
} else {
fprintf(stderr, "connect error: %s\n", strerror(err));
exit(EXIT_FAILURE);
}
}
}
} else {
perror("connect");
exit(EXIT_FAILURE);
}
close(sockfd); // 关闭socket
}
if (rp == NULL) {
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); // 释放地址信息结构体
while (1) {
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
FD_SET(sockfd, &rset);
ret = select(sockfd + 1, &rset, NULL, NULL, NULL);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
}
if (FD_ISSET(STDIN_FILENO, &rset)) {
// 从标准输入读取信息
nread = read(STDIN_FILENO, buf, BUF_SIZE);
if (nread == -1) {
perror("read");
exit(EXIT_FAILURE);
}
if (nread == 0) {
break; // EOF
}
// 将信息发送到服务器
nwrite = write(sockfd, buf, nread);
if (nwrite == -1) {
if (errno != EINTR && errno != EAGAIN) {
perror("write");
exit(EXIT_FAILURE);
}
}
}
if (FD_ISSET(sockfd, &rset)) {
// 从服务器接收信息
nread = read(sockfd, buf, BUF_SIZE);
if (nread == -1) {
if (errno != EINTR && errno != EAGAIN) {
perror("read");
exit(EXIT_FAILURE);
}
} else if (nread == 0) {
break; // 服务器关闭连接
} else {
// 将接收到的信息输出到标准输出
nwrite = write(STDOUT_FILENO, buf, nread);
if (nwrite == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
}
}
close(sockfd); // 关闭socket
return 0;
}
```
这段代码使用了非阻塞模式,通过 `select` 函数来等待可读或可写事件,从而避免了阻塞等待。同时,代码还使用了IPv6地址族和TCP协议来进行通信。
阅读全文