该网站(点击打开链接)提供了一些Linux下的IPv6的tcp/udp socket编程范例,然而经过测试发现这些实例都只能用于同一台机器间的客户端、服务器通信,当在两台机器间使用link-local地址进行通信时,可ping通,然而客户端通过connectI()无法连接上服务器,被该问题困扰许久。之后在StackOverflow找到了答案。点击打开链接
现在将tcp 的IPv6服务器、客户端编程说明如下:
一、服务器编程遵循以下流程:1、创建套接字
int socket(int domain, int type, int protocol)
该函数用于创建一个socket描述符,可唯一标识一个套接字,参数domain代表协议域,这里使用PF_INET6, type可设置是使用tcp还是udp,这里使用SOCK_STREAM,参数protocol这里不使用
2、绑定套接字
将服务端的IP地址、端口号与socket套接字进行绑定,用以给客户端提供服务,可用int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)进行绑定
3、监听套接字可调用该函数int listen(int sockfd, int backlog)进行监听,当客户端发出connect()函数时,服务器会调用accept()接收该请求。参数sockfd为套接字标识符,backlog为可接收的最大连接数。4、接收请求当客户端发起connect()请求时,服务器监听到该请求,会调用accept()函数接收请求。函数原型为int accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags); sockfd为套接字描述符,addr 为客户端的IP地址与端口号。
接下来完成网络IO操作即可。
以下为代码
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#define PORT 12345#define MESSAGE "hello"int main(void){ int sock, conn; socklen_t clilen; struct sockaddr_in6 server_addr, client_addr; char addrbuf[INET6_ADDRSTRLEN]; /* create a STREAM (TCP) socket in the INET6 (IPv6) protocol */ sock = socket(PF_INET6, SOCK_STREAM, 0); if (sock < 0) { perror("creating socket"); exit(1); }#ifdef V6ONLY // setting this means the socket only accepts connections from v6; // unset, it accepts v6 and v4 (mapped address) connections{ int opt = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) < 0) { perror("setting option IPV6_V6ONLY"); exit(1); } }#endif /* create server address: this will say where we will be willing to accept connections from */ /* clear it out */ memset(&server_addr, 0, sizeof(server_addr)); /* it is an INET6 address */ server_addr.sin6_family = AF_INET6; /* the client IP address, in network byte order */ /* in this example we accept connections from ANYwhere */ server_addr.sin6_addr = in6addr_any; /* the port we are going to listen on, in network byte order */ server_addr.sin6_port = htons(PORT); /* associate the socket with the address and port */ if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); exit(2); } /* start the socket listening for new connections */ if (listen(sock, 5) < 0) { perror("listen failed"); exit(3); } while (1) { /* now wait until we get a connection */ printf("waiting for a connection...\n"); clilen = sizeof(client_addr); conn = accept(sock, (struct sockaddr *)&client_addr, &clilen); if (conn < 0) { perror("accept failed"); exit(4); } /* now client_addr contains the address of the client */ printf("connection from %s\n", inet_ntop(AF_INET6, &client_addr.sin6_addr, addrbuf, INET6_ADDRSTRLEN)); printf("sending message\n"); write(conn, MESSAGE, sizeof(MESSAGE)); /* close connection */ close(conn); } return 0;}
二、客户端编程遵循以下流程
1、创建套接字
这个跟服务器端socketI()函数一样
2、连接服务器
客户端可用connect()函数连接服务器,服务器在监听到该连接请求时,可接受该请求。
由于IPv6中引入了 scope id域,这里需用到getaddrinfo()函数,该函数可实现IP地址、端口到addrinfo结构体的转换,具体说明日后补充。吃饭中。。。
看代码
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#define PORT "12345"#define SERVADDR "fe80::223:8bff:fe59:de90%wlan0"int main(void){ struct addrinfo hints = {0}; struct addrinfo *res; int get_err; int sockfd; char buffer[1024]; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; get_err = getaddrinfo(SERVADDR, PORT, &hints, &res); if(get_err) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(get_err)); return 1; } sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if(sockfd < 0) { perror("socket"); return 1; } if(connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); return 1; } printf("reading message\n"); read(sockfd, buffer, 1024); printf("got '%s'\n", buffer); close(sockfd); return 0;}
我想有一天和你去旅行。去那没有去过的地方,