UNP --- 第一章 介绍

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

 1 #include "unp.h"
 2 
 3 int main(int argc, char **argv)
 4 {
 5     int sockfd, n;
 6     char recvline[MAXLINE + 1];
 7     struct sockaddr_in servaddr;
 8 
 9     if (argc != 2)
10     {
11         err_quit("usage: a.out <IPaddress>");
12     }
13     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
14     {
15         err_sys("socket error");
16     }
17 
18     bzero(&servaddr, sizeof(servaddr));
19     servaddr.sin_family = AF_INET;
20     servaddr.sin_port = htons(13);
21     if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
22     {
23         err_quit("inet_pton error for %s", argv[1]);
24     }
25     if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
26     {
27         err_sys("connect error");
28     }
29 
30     while ((n = read(sockfd, recvline, MAXLINE)) > 0)
31     {
32         recvline[n] = 0;
33         if (fputs(recvline, stdout) == EOF)
34         {
35             err_sys("fputs error");
36         }
37     }
38     if (n < 0)
39     {
40         err_sys("read error");
41     }
42 }
  1. socket函数创建一个网际(AF_INET)字节流(SOCK_STREAM)套接字,即TCP套接字(TCP端点)
  2. 需要将服务器的IP地址和端口号填入sockaddr_in结构变量中,用以指定服务器套接字相关信息。该变量的地址族为AF_INET,端口号为13(时间获取服务器的知名端口)。
  3. htons用来转换二进制端口号,inet_pton将IP地址字符串转换为数值。
  4. connect函数应用于一个TCP套接字时,将与它参数中套接字指定的服务器建立TCP连接。
  5. 使用read循环读取服务器的应答。因为TCP是一个没有记录边界的字节流协议,所以daytime服务器的26个字节可以有多种返回方式,不能确保一次read就能完成所以读取。当read返回0(表示对端关闭连接)或负数(表示发生错误)时,终止循环。

错误处理:包裹函数

对于每个函数调用,都必须检查是否返回错误。当发生错误时,就使用函数输出错误信息并终止程序运行。通过定义包裹函数来完成实际的函数调用,检查返回值,并在发生错误时终止程序。如:

int Socket(int family, int type, int protocol)
{
    int n;
    if((n = socket(family, type, protocol)) < 0)
        err_sys("socket error");
    return n;
}

一个简单的时间获取服务器程序

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

int main(int argc, char* argv[])
{
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    char buff[MAXLINE + 1];
    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);

    Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
    Listen(listenfd, LISTENQ);

    while(1) {
        connfd = Accept(listenfd, NULL, NULL);
        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff));
        Close(connfd);
    }
}
  1. 调用bind函数,服务器的知名端口(13)被绑定到套接字中。IP地址为INADDR_ANY,这样要是服务器主机有多个网络接口,服务器进程就可以在任意网络接口上接受客户连接。
  2. 调用listen函数把套接字变为监听套接字。
  3. 服务器进程在accept函数中被投入休眠,等待某个客户的连接到达并被内核接受。TCP使用三次握手建立连接,建立完成后accept返回,返回值是已连接描述符,用于与新连接的客户通信。
  4. time返回秒数,ctime将该整数值变为直观可读的格式。
  5. snprintf的第二个参数指定缓冲区的大小。

网络拓扑相关命令

  1. netstat -i提供网络接口的信息。
  2. netstat -r展示路由表。
  3. ifconfig + 接口名字,可获得各接口的详细信息。
  4. 为了找出本地网络众多主机IP地址,可ping本地接口的广播地址。

猜你喜欢

转载自www.cnblogs.com/hlk09/p/10356967.html