【Socket编程】Linux下的IPv6 socke编程

该网站(点击打开链接)提供了一些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;
}



                                        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值