一个简单的时间获取客户端/服务器程序(疑难解决)

刚开始学习UNIX网络编程,碰到很多小问题,写下来方便以后遇到类似问题快速解决。

系统:centos

搭建unix网络编程环境

1.下载本书的头文件及示例源码

http://www.apuebook.com/code3e.html

2.解压unpv1.e.tar.gz后进入目录查看README,然后可以按照里面提示操作,不过会遇到问题

第一步:在终端中进入upnv13e目录,然后执行代码:

[python]  view plain  copy
  1. ./configure  

第二步:这里有问题及解决方法

[python]  view plain  copy
  1. cd lib  
[python]  view plain  copy
  1. make  //这一步我出错了  

错误代码为:

[python]  view plain  copy
  1. gcc -g -O2 -D_REENTRANT -Wall   -c -o connect_nonb.o connect_nonb.c  
  2. In file included from connect_nonb.c:1:  
  3. unp.h:114: error: redefinition of ‘struct in_pktinfo’  
  4. make: *** [connect_nonb.o] 错误 1  

redefinition of ‘struct in_pktinfo’的解决方法如下: 

结构in_pktinfo已经包含在标准头文件bits/in.h中了, 它又通过 netinet/in.h 在unp.h中被包括进来. 只要将 unp.h 中的结构定义comment out注释掉就行了. 

注释掉之后重新

[python]  view plain  copy
  1. make //build the basic library that all programs need  

这次就成功了!生成了../libunp.a文件。

第三步:这一步没有问题

[python]  view plain  copy
  1. cd ../libfree  # continue building the basic library  
  2. make  
第四步:这步解决方法麻烦一点
[python]  view plain  copy
  1. cd ../libgai   # the getaddrinfo() and getnameinfo() functions  
  2. make  
错误提示如下:
[python]  view plain  copy
  1. gcc -g -O2 -D_REENTRANT -Wall   -c -o getaddrinfo.o getaddrinfo.c  
  2. getaddrinfo.c: In function ‘getaddrinfo’:  
  3. getaddrinfo.c:58: error: ‘EAI_ADDRFAMILY’ undeclared (first use in this function)  
  4. getaddrinfo.c:58: error: (Each undeclared identifier is reported only once  
  5. getaddrinfo.c:58: error: for each function it appears in.)  
  6. getaddrinfo.c:116: error: ‘EAI_NODATA’ undeclared (first use in this function)  
  7. make: *** [getaddrinfo.o] 错误 1  

解决方法如下:

回到unpv13e目录: 

[python]  view plain  copy
  1. cd ..  
  2. gedit configure.in   
找到下面一行注释掉
LIBGAI_OBJS="getaddrinfo.o getnameinfo.o freeaddrinfo.o gai_strerror.o"
然后用下面的代码代替注释掉的那行

  1. LIBGAI_OBJS=
  2. if test "$ac_cv_func_getaddrinfo" = no ; then
  3. LIBGAI_OBJS="$LIBGAI_OBJS getaddrinfo.o"
  4. fi
  5. if test "$ac_cv_func_getnameinfo" = no ; then
  6. LIBGAI_OBJS="$LIBGAI_OBJS getnameinfo.o"
  7. fi
  8. if test "$ac_cv_func_freeaddrinfo" = no ; then
  9. LIBGAI_OBJS="$LIBGAI_OBJS freeaddrinfo.o"
  10. fi
  11. if test "$ac_cv_func_gai_strerror" = no ; then
  12. LIBGAI_OBJS="$LIBGAI_OBJS gai_strerror.o"
  13. fi
[python]  view plain  copy
  1. autoconf  
  2. ./configure  
[python]  view plain  copy
  1. gedit Make.defines   
在文件末尾加上下面这句:
CFLAGS = -g -O2 -D_REENTRANT -Wall -D_GNU_SOURCE

然后重新执行代码:

[python]  view plain  copy
  1. cd libgai  # continue building the basic library  
  2. make  

ok,问题解决了!

4,将生成的libunp.a静态库复制到/usr/lib/和/usr/lib64/中。

[html]  view plain  copy
  1. cd ..   //回到unpv12e目录  
[html]  view plain  copy
  1. sudo cp libunp.a /usr/lib  
  2. sudo cp libunp.a /usr/lib64  
5,修改unp.h并将其和config.h拷贝到/usr/include中,为了以后include方便
[python]  view plain  copy
  1. gedit lib/unp.h   //将unp.h中#include "../config.h"修改为#include "config.h"  
[python]  view plain  copy
  1. sudo cp lib/unp.h /usr/include  
  2. sudo cp config.h /usr/include  
6,编译源代码
[python]  view plain  copy
  1. cd ./intro  
  2. gcc daytimetcpcli.c -o daytimetcpcli -lunp  

跟普通的编译不一样的是要在最后加上刚才那个链接库,-l参数加上刚才那个libunp.a去掉lib和后面的.a。最后得到参数-lunp。

7,编写程序

以后编写完的程序安装6中的代码编译就行了,然后代码可以完全跟书上的一样。代码编辑器或IDE等就按自己的喜好来选了。这个网上很多c语言编程环境搭建教程。

客户端程序

#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 ");   
	if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
		err_sys("socket error");  
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(9999);
	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, 1)) >0 ){  
        recvline[n]=0;  
		if (fputs(recvline,stdout) == EOF) {       
                err_sys("fputss error");  
			break;
        }  
    }  
	if (n < 0)
			err_sys("read error");  
	exit(0);
}

服务器程序

#include    "unp.h"
#include    
int Socket(int family, int type, int protocol)
{
    int n;
    if((n = socket(family, type, protocol)) < 0)
        printf("socket error\n");
    return(n);
}
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(9999);

    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));

        close(connfd);
    }
}

注意htons参数送入9999.并且编译err_sys等函数会报错,因为这是作者自己编写的函数,我们可以自己编写。

my_err.h

#include  /* for definition of errno */
#include  /* ISO C variable aruments */

static void err_doit(int, int, const char *, va_list);

/*
 * Nonfatal error related to a system call.
 * Print a message and return.
 */
void
err_ret(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
}


/*
 * Fatal error related to a system call.
 * Print a message and terminate.
 */
void
err_sys(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Fatal error unrelated to a system call.
 * Error code passed as explict parameter.
 * Print a message and terminate.
 */
void
err_exit(int error, const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Fatal error related to a system call.
 * Print a message, dump core, and terminate.
 */
void
err_dump(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    abort(); /* dump core and terminate */
    exit(1); /* shouldn't get here */
}


/*
 * Nonfatal error unrelated to a system call.
 * Print a message and return.
 */
void
err_msg(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
}


/*
 * Fatal error unrelated to a system call.
 * Print a message and terminate.
 */
void
err_quit(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
    exit(1);
}


/*
 * Print a message and return to caller.
 * Caller specifies "errnoflag".
 */
static void
err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char buf[MAXLINE];
   vsnprintf(buf, MAXLINE, fmt, ap);
   if (errnoflag)
       snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
         strerror(error));
   strcat(buf, "\n");
   fflush(stdout); /* in case stdout and stderr are the same */
   fputs(buf, stderr);
   fflush(NULL); /* flushes all stdio output streams */
}
然后把该文件移动到/usr/include/下

sudo cp my_err.h /usr/include

包含该函数  重新编译成功。注意 运行时,服务器端与客户端程序要都运行


你可能感兴趣的:(Unix网络编程)