刚开始学习UNIX网络编程,碰到很多小问题,写下来方便以后遇到类似问题快速解决。
系统:centos
搭建unix网络编程环境
http://www.apuebook.com/code3e.html
2.解压unpv1.e.tar.gz后进入目录查看README,然后可以按照里面提示操作,不过会遇到问题
第一步:在终端中进入upnv13e目录,然后执行代码:
- ./configure
第二步:这里有问题及解决方法
错误代码为:
- gcc -g -O2 -D_REENTRANT -Wall -c -o connect_nonb.o connect_nonb.c
- In file included from connect_nonb.c:1:
- unp.h:114: error: redefinition of ‘struct in_pktinfo’
- make: *** [connect_nonb.o] 错误 1
redefinition of ‘struct in_pktinfo’的解决方法如下:
结构in_pktinfo已经包含在标准头文件bits/in.h中了, 它又通过 netinet/in.h 在unp.h中被包括进来. 只要将 unp.h 中的结构定义comment out注释掉就行了.
注释掉之后重新
- make //build the basic library that all programs need
这次就成功了!生成了../libunp.a文件。
第三步:这一步没有问题
第四步:这步解决方法麻烦一点
- cd ../libfree # continue building the basic library
- make
错误提示如下:
- cd ../libgai # the getaddrinfo() and getnameinfo() functions
- make
- gcc -g -O2 -D_REENTRANT -Wall -c -o getaddrinfo.o getaddrinfo.c
- getaddrinfo.c: In function ‘getaddrinfo’:
- getaddrinfo.c:58: error: ‘EAI_ADDRFAMILY’ undeclared (first use in this function)
- getaddrinfo.c:58: error: (Each undeclared identifier is reported only once
- getaddrinfo.c:58: error: for each function it appears in.)
- getaddrinfo.c:116: error: ‘EAI_NODATA’ undeclared (first use in this function)
- make: *** [getaddrinfo.o] 错误 1
解决方法如下:
回到unpv13e目录:
找到下面一行注释掉
- cd ..
- gedit configure.in
LIBGAI_OBJS="getaddrinfo.o getnameinfo.o freeaddrinfo.o gai_strerror.o"
然后用下面的代码代替注释掉的那行
- LIBGAI_OBJS=
- if test "$ac_cv_func_getaddrinfo" = no ; then
- LIBGAI_OBJS="$LIBGAI_OBJS getaddrinfo.o"
- fi
- if test "$ac_cv_func_getnameinfo" = no ; then
- LIBGAI_OBJS="$LIBGAI_OBJS getnameinfo.o"
- fi
- if test "$ac_cv_func_freeaddrinfo" = no ; then
- LIBGAI_OBJS="$LIBGAI_OBJS freeaddrinfo.o"
- fi
- if test "$ac_cv_func_gai_strerror" = no ; then
- LIBGAI_OBJS="$LIBGAI_OBJS gai_strerror.o"
- fi
- autoconf
- ./configure
在文件末尾加上下面这句:
- gedit Make.defines
CFLAGS = -g -O2 -D_REENTRANT -Wall -D_GNU_SOURCE
然后重新执行代码:
- cd libgai # continue building the basic library
- make
ok,问题解决了!
4,将生成的libunp.a静态库复制到/usr/lib/和/usr/lib64/中。
跟普通的编译不一样的是要在最后加上刚才那个链接库,-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
包含该函数 重新编译成功。注意 运行时,服务器端与客户端程序要都运行