1、《UNIX网络编程》——概述

1、源码编译网络

一、源码下载数据结构

二、编译socket

$tar zxvf unpv13e.tar.gz函数

$cd unpv13eui

参照README进行编译spa

2、实例随笔code

数据从一层传到相应层,要经历封装->封装->封装->解封->解封->解封server

一、一个简单的时间获取客户端程序blog

#include    "unp.h"

int
main(int argc, char **argv)
{
    int                    sockfd, n;
    char                recvline[MAXLINE + 1];
    struct sockaddr_in    servaddr;

    if (argc != 2)
        err_quit("usage: a.out <IPaddress>");

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    //创建socket链接,AF_INET:IPv4 SOCK_STREAM:字节流套接字    后面章节会详细介绍
        err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));                        //对地址结构初始化
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(13);    /* daytime server */
    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
        err_quit("inet_pton error for %s", argv[1]);

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)    //向目的端发送链接请求
        err_sys("connect error");

    while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
        recvline[n] = 0;    /* null terminate */
        if (fputs(recvline, stdout) == EOF)                    //将发送过来的数据打印到标准输出
            err_sys("fputs error");
    }
    if (n < 0)
        err_sys("read error");

    exit(0);
}

相应重要数据结构队列

struct sockaddr_in
 
{
 
short sin_family;/*Address family通常来讲AF_INET(地址族)PF_INET(协议族)*/
 
unsigned short sin_port;/*Port number(必需要采用网络数据格式,普通数字能够用htons()函数转换成网络数据格式的数字)*/
 
struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/
 
unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
 
};

 

个人Makefile(这里不做多余解释)

其中 "unp.h" 我直接从源代码中(unpv12e/lib/unp.h)拷贝到我本身的目录中(myunp/lib/unp.h)

编译后运行

这里会报错(connect error),缘由是咱们在本地并无开启端口为13的时间服务(莫急,后面会有相应的服务端代码)

----

关于IPv6的版本,就是把sockaddr_in 变成了 sockaddr_in6 其AF_INET 改为 AF_INET6

#include    "unp.h"

int
main(int argc, char **argv)
{
    int                    sockfd, n;
    struct sockaddr_in6    servaddr;
    char                recvline[MAXLINE + 1];

    if (argc != 2)
        err_quit("usage: a.out <IPaddress>");

    if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
        err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin6_family = AF_INET6;
    servaddr.sin6_port   = htons(13);    /* daytime server */
    if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)
        err_quit("inet_pton error for %s", argv[1]);

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
        err_sys("connect error");

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

    exit(0);
}

 

----

二、包裹函数

在不用包裹函数的代码中,常常要出现错误输出处理的代码,好比

包裹函数对其进行封装,用一个简单的函数来完成了错误处理,这里是把开头字母换成了大写

三、时间获取服务端程序

#include    "unp.h"
#include    <time.h>

int
main(int argc, char **argv)
{
    int                    listenfd, connfd;    //监听文件描述符 链接文件描述符
    struct sockaddr_in    servaddr;            
    char                buff[MAXLINE];
    time_t                ticks;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(13);    /* daytime server */

    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));    //把本地协议地址富裕一个套接字

    Listen(listenfd, LISTENQ);                //unp.h => LISTENQ=1024

    for ( ; ; ) {
        connfd = Accept(listenfd, (SA *) NULL, NULL);    //用于从已完成链接队列对头返回下一个已完成链接

        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));//获取时间信息,存入缓冲区
        Write(connfd, buff, strlen(buff));

        Close(connfd);
    }
}

编译运行

这样服务端程序就开启了,如今我们就能够再运行第一个获取时间的客户端程序

获取到了时间信息

 

以上。

相关文章
相关标签/搜索