Unix网络编程(一)基本字段和常用函数

Unix网络编程(一)基本字段和常用函数

1.基本字段
2.常用函数

基本字段

      用来表示地址的结构有两个,都是定义在in.h中,分别是sockaddr_in和sockaddr。通常定义并初始化sockaddr_in,在使用函数传递参数时将其强转为后者,因为在大多数函数中,要求的指针类型都sockaddr,然而sockaddr_in的字段较为丰富,容易赋值。

具体的字段定义如下

sockaddr_in

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

sockaddr

/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    /* Common data: address family and length.  */
    char sa_data[14];       /* Address data.  */
  };

在这里特别要提的是
第一个字段__SOCKADDR_COMMON 在sockaddr.h中定义为

#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family

就是以前的sa_family_t类型的名为sin_family的字段。代表着该socket使用的协议族。常用的有AF_INET和AF_INET6,前者代表Ipv4,后者代表Ipv6。

以及sockaddr_in的最后一个字段sin_zero,它是通过计算,让sockaddr_in和sockaddr保持同样的空间大小,保证转换时的完整性。

基本函数

socket()

     int socket(int domain, int type, int protocol);

作用:建立一个新的socket
返回值:成功则返回socket对应的代码,失败则为-1
参数:
   1.第一个参数指定何种类型的协议族,常用有AF_INET和AF_INET6两种。完整的定义在/usr/include/bits/socket.h 内
  2.第二个参数指定类型,常用的是SOCK_STREAM(TCP协议),SOCK_DGRAM(UDP协议)。
  3.第三的参数指定传输协议,但因为会自动设置为type参数所对应的协议。因此设置为0即可

connect()

    int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);

作用:将socket 连至参数serv_addr 指定的网络地址
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中.
参数:
    1.第一个是socket
    2.第二个是sockaddr的指针
    3.第三个是指针的长度(大小)

bind()

    int bind (int sockfd, struct sockaddr * my_addr, int addrlen)

作用:用于将本地地址与socket捆绑
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中.
参数:
    1.第一个是socket
    2.第二个是sockaddr的指针
    3.第三个是指针的长度(大小)

listen()

    int listen (int __fd, int __n)

作用:监听申请的连接
返回值:正确则返回0。否则的话,返回SOCKET_ERROR错误
参数:
   1.第一个为socket的描述符
   2.第二个为等待连接队列的最大长度。

accept()

    int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)

作用:接受来自指定socket的请求,并为该请求分配一个新的描述符
返回值:成功则返回新的socket 处理代码, 失败返回-1, 错误原因存于errno 中.
参数:
   1. 第一个参数socket的描述符
    2.第二个是sockaddr的指针
    3.第三个是指针的长度(大小)

close()

    int close (int __fd)

作用:释放对应的文件描述词
返回值:若文件顺利关闭则返回0, 发生错误时返回-1.
参数:

代码

以下是两个例子,
第一个是向13端口请求数据。(13端口是daytime服务的端口,返回所在主机的时间。因此运行时要求开启13端口)。
第二个是模拟daytime服务器,对访问13端口的请求返回主机时间。


请求13端口
#include    <sys/socket.h>  /* basic socket definitions */
#include    <netinet/in.h>

int main()
{
    int                 sockfd, n;
    char                recvline[MAXLINE + 1];
    struct sockaddr_in  servaddr;
    char *IPaddress = "127.0.0.1";

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    /*创建socket*/
        printf("socket error");

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(13);    /* 13端口是daytime服务 */
    if (inet_pton(AF_INET, IPaddress, &servaddr.sin_addr) <= 0) /*该函数将字符型表达(presentation)转换位数值(number)*/
        printf("inet_pton error for %s", argv[1]);

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)/*建立连接*/
        printf("connect error");

    while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {    /*读取流信息*/
        recvline[n] = 0;    /* null terminate */
        if (fputs(recvline, stdout) == EOF)
            printf("fputs error");
    }
    if (n < 0)
        printf("read error");

    exit(0);
}
    模拟daytime服务
    #include    <sys/socket.h>  /* basic socket definitions */
#include    <netinet/in.h>
#include    <time.h>

int
main(int argc, char **argv)
{
    int                 listenfd, connfd;
    socklen_t           len;
    struct sockaddr_in  servaddr, cliaddr;
    char                buff[MAXLINE];
    time_t              ticks;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);/*创建socket*/

    bzero(&servaddr, sizeof(servaddr));     /*初始化servaddr,将其清空为0.可用memset函数代替,以下三步为其字段赋值*/
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   /*INADDR_ANY为0x00000000 ,意为接收任何来到该地址的请求*/
    servaddr.sin_port        = htons(13);   

    bind(listenfd, (SA *) &servaddr, sizeof(servaddr));     /*将socket与本机指定端口和地址捆绑*/

    listen(listenfd, LISTENQ);  /*开启监听*/

    for ( ; ; ) {
        len = sizeof(cliaddr);
        connfd = accept(listenfd, (SA *) &cliaddr, &len); /*当有连接时,将该连接的句柄绑定到connfd上*/
        printf("connection from %s, port %d\n",     /*打印请求地址*/
               Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
               ntohs(cliaddr.sin_port));

        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));   /*返回时间*/
        write(connfd, buff, strlen(buff));

        close(connfd);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值