初识linux socket编程
csapp.h的配置
在编译链接hex2dd.c时,报错 undefined reference to 'unix_error' collect2: error: ld returned 1 exit status
,
于是我擅自把unix_error的内容拿出来写进hex2dd.c。而在dd2hex.c中,apt_error和unix_error两个函数都报错。
我决定解决这个错误。通过生成动态库的方法:
首先依次执行
// 当前路径下有csapp.h和csapp.c
gcc -shared -fpic -o libcsapp.so csapp.c -lpthread
sudo mv libcsapp.so /usr/local/lib
然后执行gcc dd2hex.c -o dd2hex -lcsapp
并运行程序
发现编译没有报错,而运行时报错了。这是由于运行时链接没有找到动态库。
尝试来到/etc/ld.so.conf.d/下新建一个文件添加/usr/local/lib为寻找动态库的地址,发现已经有一个文件内含有这个地址
执行sudo ldconfig
更新ld.so.cache,然后即可成功运行。
改变IP地址的表示形式
十六进制转为点分十进制
/*hex2dd.c*/
#include"csapp.h"
int main(int argc, char **argv)
{
struct in_addr inaddr; // 网络字节序
uint32_t addr; // 主机字节序
char buf[MAXBUF]; // 点分十进制
if (argc != 2)
{
fprintf(stderr, "usage: %s <hex number>\n", argv[0]);
exit(0);
}
sscanf(argv[1], "%x", &addr);
inaddr.s_addr = htonl(addr);
if (!inet_ntop(AF_INET, &inaddr, buf, MAXBUF))
fprintf(stderr, "%s: %s\n", "inet_ntop", strerror(errno));
printf("%s\n", buf);
exit(0);
}
编译命令:gcc hex2dd.c -o hex2dd
(需要把csapp.h和csapp.c放在当前路径)
运行效果:
IP地址结构定义如下:
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
一个IP地址就是一个32位无符号整数,所以上述程序也可以改写成如下:
/*hex2dd_1.c*/
#include"csapp.h"
int main(int argc, char **argv)
{
uint32_t inaddr; // 网络字节序
uint32_t addr; // 主机字节序
char buf[MAXBUF]; // 点分十进制
if (argc != 2)
{
fprintf(stderr, "usage: %s <hex number>\n", argv[0]);
exit(0);
}
sscanf(argv[1], "%x", &addr);
inaddr = htonl(addr);
if (!inet_ntop(AF_INET, &inaddr, buf, MAXBUF))
fprintf(stderr, "%s: %s\n", "inet_ntop", strerror(errno));
printf("%s\n", buf);
exit(0);
}
sscanf函数指定了输入源为argv[1],以16进制格式输入;
#include<arpa/inet.b>
uint32_t htonl(uint32_t hostlong);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
htonl函数把主机字节顺序转换为网络字节顺序;
inet_ntop函数将十六进制转换为点分十进制。
点分十进制转为十六进制
/*dd2hex.c*/
#include"csapp.h"
int main(int argc, char **argv)
{
struct in_addr inaddr;
int rc;
uint32_t addr;
if (argc != 2)
{
fprintf(stderr, "usage: %s <dotted-decimal>\n", argv[0]);
exit(0);
}
rc = inet_pton(AF_INET, argv[1], &inaddr);
if (rc == 0)
app_error("inet_pton error: invalid dotted-decimal address");
else if (rc < 0)
unix_error("inet_pton error");
printf("0x%x\n", ntohl(inaddr.s_addr));
exit(0);
}
编译命令:gcc dd2hex.c -o dd2hex -lcsapp
(提前配置好动态库)
运行效果:
#include <arpa/inet.h>
uint32_t ntohl(uint32_t netlong);
int inet_pton(int af, const char*src, void *dst);
ntohl函数把网络字节序转换为主机字节序;
inet_pton函数把点分十进制转换为十六进制。
将域名转换为IP地址
/*hostinfo.c*/
#include "csapp.h"
int main(int argc, char **argv)
{
struct addrinfo *p, *listp, hints;
char buf[MAXLINE];
int rc, flags;
if (argc != 2)
{
fprintf(stderr, "usage: %s <domain name>\n", argv[0]);
exit(0);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // 查找32的IP地址
hints.ai_socktype = SOCK_STREAM; // 用作连接的端点
if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) // service设为NULL
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc));
exit(1);
}
flags = NI_NUMERICHOST;
for (p = listp; p; p = p->ai_next)
{
getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINE, NULL, 0, flags);
printf("%s\n", buf);
}
freeaddrinfo(listp);
exit(0);
}
运行效果:
/* Structure to contain information about address of a service provider. */
struct addrinfo
{
int ai_flags; /* Input flags. */
int ai_family; /* Protocol family for socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol for socket. */
socklen_t ai_addrlen; /* Length of socket address. */
struct sockaddr *ai_addr; /* Socket address for socket. */
char *ai_canonname; /* Canonical name for service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
getaddrinfo的host参数可以是域名也可以是数字地址,service参数可以是服务名也可以是十进制端口号。必须指定两者中至少一个。通过hints参数设置个别字段,ai_family设置为AF_INET会将列表限制为IPv4地址,设置为AF_INET6则限制为IPv6地址;ai_socketype设置为SOCK_STREAM将列表限制为对每个地址最多一个addrinfo结构;返回result,result是一个指向addrinfo结构的链表,其中每个结构指向一个对应于host和service的套接字地址结构。
参考
深入理解计算机系统(原书第3版)
csapp.h头文件的使用 ---- 3种方法运行《深入理解计算机系统》中的代码
Linux动态库的查找路径