unix网络编程学习
最近抽时间学习UNIX网络编程,通过网络和书中的知识将以前落下的内容尽量补上来,因为以前基本上做windows相关开发,用到的网络方便的技术比较少,也没有进行深入研究,linux和网络编程这块是个短板,看书然后写一下例子程序,这期间一定会遇到各种问题,问题涉及环境搭建、网络编程、编译器、操作系统等不同方面,力求通过解决这些问题来建立起自己的“技术知识库”。
1.环境的搭建
.在执行例子之前,需要对于环境进行搭建(否则会出现各种undefined reference的问题);以下是网上查找以及自己领悟的一点点东西:我用的是CentOS系统,前期自己装了编译器,版本为4.4.7;
下载源码:我使用的是unpv13e.tar.gz ,解压到本地,按照编译其他源码类似的方式进行编译安装:
1) 运行configure并make
<pre name="code" class="plain">cd unp13e
chmod u+x configure
./configure
cd lib
make
2)生成类库和函数库
cd libfree
make
cd lib gai
make
make的时候会出现以下错误,这是因为变量定义的类型问题。
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o in_cksum.o in_cksum.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o inet_ntop.o inet_ntop.c
inet_ntop.c: In function ‘inet_ntop’:
inet_ntop.c:61: error: argument ‘size’ doesn’t match prototype
/usr/include/arpa/inet.h:65: error: prototype declaration
打开inet_ntop.c文件,在第61行,可以发现size是有问题的,打开inet.h,对比函数原型,发现size应该改为socklen_t 即可(在64位系统上,socklen_t和size_t大小不一样,系统差异带来的问题)
extern __const char *inet_ntop (int __af, __const void *__restrict __cp,char *__restrict __buf, socklen_t __len) __THROW;
经过上述步骤之后,会生成libunp.a的静态库,为了以后的使用,最好将这个库加入到系统常用库目录中,避免编译路径的问题
3)拷贝库文件到lib目录
<pre name="code" class="plain">sudo cp libunp.a /usr/lib
sudo cp libunp.a /usr/lib64
使用root用户或者添加sudo
在lib/unp.h中,修改include config.h的路径,改为:
#include “config.h”
4)拷贝头文件到/usr/include/
sudo cp lib/unp.h /usr/include
sudo cp config.h /usr/include
第四步主要是为了以后构建程序方便;
5)编译源代码
cd ./intro
gcc -o xxxx xxxx.c -lunp
这里会有个问题,如果代码中使用了err_sys、err_quit等错误输出,就会报was not declared的错误,这是因为编译器找不到函数这些函数是坐着自己封装的,需要我们在代码中加入,
具体是在/usr/inlcude目录下创建一个xxxx.h文件,拷贝以下内容:
#include "apue.h"
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* 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, " ");
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(NULL); /* flushes all stdio output streams */
}
注意apue.h是作者写的头文件,需要下载,我下载的是最新版apue.3e,不需要修改里面的内容,直接
sudo cp apue.3e/inlcude/apue.h /usr/include/
再编译程序应该就没有问题了。
如果出现下面的错误提示:
/tmp/ccA6KxDT.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' collect2: ld returned 1 exit status
这是因为文件后缀名称引起的,我当时写的代码是.cpp,使用gcc编译不加 -lstdc++ 就会出现这个问题;后来查了查,发现gcc编译cpp文件,但是在链接的时候,没有链接到c++的标准库,而-lstdc++对应的就是标准的c++库;
环境搭建不难,遇到问题通过分析也能找到原因,在分析问题的过程中,会涉及的各个方面,比如编译器,操作系统等等,都是值得发掘的。