IPV6 Socket编程

来源:互联网 发布:.net软件开发工程师 编辑:程序博客网 时间:2024/05/22 04:38


IPV6 socket的练习程序,服务器打印客户端的地址,然后回送收到的消息。

server_v6.c

/************************************************************Copyright (C), 2017, Leon, All Rights Reserved.FileName: server_v6.cDescription: IPV6网络编程练习Author: LeonVersion: 1.0Date: 2017-2-9 11:09:39Function:History:<author>    <time>  <version>   <description> Leon************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#define BUF_LEN 2048#define PORT 10023int main(int argc, char *argv[]){    int serv_sock = -1, client_sock = -1;    socklen_t addr_len = 0;    struct sockaddr_in6 local_addr = {0}, client_addr = {0};    char buf[BUF_LEN] = {0};    int err = -1;    /* 建立socket */    serv_sock = socket(PF_INET6, SOCK_STREAM, 0);    if(-1 == serv_sock)    {        perror("socket error: ");        return -1;    }    /* 填充地址结构 */    local_addr.sin6_family = AF_INET6;    local_addr.sin6_port = htons(PORT);    local_addr.sin6_addr = in6addr_any;    /* 绑定地址 */    err = bind(serv_sock, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in6));    if(-1 == err)    {        perror("bind error: ");        close(serv_sock);        return -1;    }    /* 监听 */    err = listen(serv_sock, 5);    if(-1 == err)    {        perror("listen error: ");        close(serv_sock);        return -1;    }    /* 循环等待客户连接请求 */    while(1)    {        memset(&client_addr, 0x0, sizeof(client_addr));        addr_len = sizeof(struct sockaddr_in6);        client_sock = accept(serv_sock, (struct sockaddr *)&client_addr, &addr_len);        if(-1 == client_sock)        {            perror("accept error:");            close(serv_sock);            return -1;        }        /* 转换client地址为字符串并打印 */        inet_ntop(AF_INET6, &client_addr.sin6_addr, buf, BUF_LEN);        printf("A clinet connected, ip: %s, port %d\n", buf, ntohs(client_addr.sin6_port));        /* 接收消息 */        memset(buf, 0x0, BUF_LEN);        err = recv(client_sock, buf, BUF_LEN, 0);        if(err < 0)        {            perror("recv error:");            close(serv_sock);            close(client_sock);            return -1;        }        printf("recv %d bytes: %s\n", err, buf);        /* 回送消息 */        err = send(client_sock, buf, strlen(buf), 0);        if(err < 0)        {            perror("send error:");            close(serv_sock);            close(client_sock);            return -1;        }        /* 关闭这个client连接 */        close(client_sock);    }    return 0;}

client_v6.c

/************************************************************Copyright (C), 2017, Leon, All Rights Reserved.FileName: client_v6.cDescription: IPV6网络编程练习Author: LeonVersion: 1.0Date: 2017-2-9 11:09:39Function:History:<author>    <time>  <version>   <description> Leon************************************************************/// connect时地址长度填错,一直报这个错 connect error:: Invalid argument#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#define BUF_LEN 2048#define PORT 10023int main(int argc, char *argv[]){    int sock = -1;    socklen_t addr_len = 0;    struct sockaddr_in6 serv_addr = {0};    char buf[BUF_LEN] = {0};    int err = -1;    /* 建立socket */    sock = socket(AF_INET6, SOCK_STREAM, 0);    if(-1 == sock)    {        perror("socket error: ");        return -1;    }    memset(&serv_addr, 0x0, sizeof(serv_addr));    /* 填充地址结构 */    serv_addr.sin6_family = AF_INET6;    serv_addr.sin6_port = htons(PORT);    serv_addr.sin6_addr = in6addr_loopback;    /* 连接到环回地址 */    // 不能connect到链路本地地址    // inet_pton(AF_INET6, "fe80::20c:29ff:fe8f:c168", &serv_addr.sin6_addr);    addr_len = sizeof(serv_addr);    err = connect(sock, (struct sockaddr *)&serv_addr, addr_len);    if(-1 == err)    {        perror("connect error:");        close(sock);        return -1;    }    /* 发送消息 */    memset(buf, 0x0, BUF_LEN);    snprintf(buf, BUF_LEN - 1, "hello server, I'm client\n");    err = send(sock, buf, strlen(buf), 0);    if(err < 0)    {        perror("send error:");        close(sock);        return -1;    }    /* 接收消息 */    memset(buf, 0x0, BUF_LEN);    err = recv(sock, buf, BUF_LEN, 0);    if(err < 0)    {        perror("recv error:");        close(sock);        return -1;    }    printf("recv %d bytes: %s\n", err, buf);    close(sock);    return 0;}

运行结果

root@ubuntu:ipv6_socket# ./server_v6A clinet connected, ip: ::1, port 56358recv 25 bytes: hello server, I'm clientA clinet connected, ip: ::ffff:192.168.242.1, port 11111recv 12 bytes: 123456478764

第一个客户端为上面程序实现的客户端,connect的本地环回地址。第二个客户端为一个IPV4的客户端,connect的192.168.242.2的地址。可以看到对于支持双栈的IPV6服务器,一样可以接受IPV4客户端的连接和通信,IPV4客户端打印出来的地址为IPV4映射的IPV6地址,这些都由协议栈处理好了。附一张图:
Alt text

注意点

  • 客户端connect时不能连接到链路本地地址(fe80开头那个地址),否则会报connect error:: Invalid argument的错误,可以connect环回地址,或者用命令ip addr add 2001::1/64 dev eth0为接口添加一个IPV6地址。connect的地址长度入参错了,也会报这个错
0 0