Unix Network Programming(1)---基本概念说法

本文介绍了一个使用C语言实现的简单时间获取服务器程序,通过socket编程实现与客户端的连接,接收客户端请求并返回当前时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个简单的时间获取函数(客户)

    #include 'unp'   //包含自己编写的头文件,该头文件包含大多数网络程序都需要的许多系统头文件,并定义了所用到的各种常值
    int main(int argc, char **argv)    //main函数形参是命令行参数
    {
        int sockfd,n;
        char recvline[MAXLINE+1];
        struct sockaddr_in servaddr;

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

        /* socket函数创建一个网际(AF_INET)字节流(SOCK_STREAM)套接字。该函数返回一个小整数描述符,
           以后所有函数调用(如随后read和connect)都用该描述符描述该套接字。*/
        if ( (sockfd=socket(AF_INET,SOCK_STREAM,0) )<0)    
            err_sys("socket error");

        /*指定服务器的IP地址和端口*/
        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");       //SA在unp.h中是用#define定义为struct sockaddr

        /*读入并输出服务器的应答*/
        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);
    }

Key Points

  • bzero()函数将结构清零, 两个参数.memset()函数也可以实现同样功能,但它有三个参数.
  • 网际套接字地址结构中的IP地址与端口号这两个成员必须是用特定的格式.
    库函数htons(“主机到网络短整数”)去转换二进制端口号.
    库函数inet_pton(“呈现形式到数值”)去把ASCII命令行参数转化位合适格式.
  • SA代表struct sockaddr,即通用套接字地址结构.每当一个套接字函数需要一个指向某个套接字地址结构的指针时,这个指针必须强制类型转化成一个指向通用套接字地址结构的指针.
  • read()函数读取服务器的应答,标准io函数fputs输出结果.如果数据很大,我们不能确保一次read调用就能返回服务器的整个应答,因此从TCP套接字读取数据时,我们总是需要把read编写在某个循环中,read返回0(表明对端关闭连接)或负值(表明发生错误)时终止循环.

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

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

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

    /*TCP套接字的创建与客户程序相同*/
    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);

    /*接收客户连接,发送应答*/
    for(;;)
    {
        connfd=Accept(listenfd,(SA *) NULL,NULL);

        ticks=time(NULL);
        snprintf(buff,sizeof(buff),"%.24s\r\n",ctime(&ticks));
        Write(connfd,buff,strlen(buff));

        /*终止连接,该调用引发TCP连接关闭的四次握手*/
        Close(connfd);
    }
}

Key Points

  • 指定IP地址为INADDR_ANY,这样要是服务器主机由多个网络接口,服务器进程就可以在任意网络接口上接受客户连接。
  • 调用listen函数把该套接字转换成一个监听套接字,这样客户的外来连接就可以该套接字上由内核接收。常值LISTENQ定义在unp.h中,他用来指定内核允许在这个监听描述符上排队的最大客户连接数。
  • 服务器进程在accept调用后投入睡眠,等待某个客户连接到达并被内核接收。三次握手来建立连接,握手完毕时accept返回,返回一个**已连接描述符**connfd。该描述符用于与新近连接的那个客户通信。
  • 本服务器一次只能处理一个客户,称为迭代服务器。同时能处理多个客户的称为并发服务器,最简单的是使用fork函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值