参考地址:http://www.wangafu.net/~nickm/libevent-book/01_intro.html#_footnote_1
在阅读libevent文档时发现这个例子,文档列出这个例子的重点是说明阻塞式编程。因为对C网络编程还不太懂,这里添加了一些注释。
/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For gethostbyname */
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(int c, char **v)
{
//\r表示回车,\n表示换行
//发送这些信息,应该相当于发送了一个GET请求。利用socket来发送get请求
const char query[] =
"GET / HTTP/1.0\r\n"
"Host: www.baidu.com\r\n"
"\r\n";
const char hostname[] = "www.baidu.com";
//套接字地址结构,在Unix网络编程中有描述
struct sockaddr_in socketAddr_in;
//对一个主机的描述,有地址,主机名等
struct hostent *baiduhost;
const char *cp;
int fd;
ssize_t n_written, remaining;
char buf[1024];
/* Look up the IP address for the hostname. Watch out; this isn't
threadsafe on most platforms. */
baiduhost = gethostbyname(hostname); //gethostbyname是阻塞的,得不到地址不返回
if (!baiduhost) {
fprintf(stderr, "Couldn't lookup %s: %s", hostname, hstrerror(h_errno));
return 1;
}
if (baiduhost->h_addrtype != AF_INET) {
fprintf(stderr, "No ipv6 support, sorry.");
return 1;
}
/* Allocate a new socket,Returns a file descriptor for the new socket, or -1 for errors. */
//the first is the address domain of the socket. recall that there are two possile address domains
//the unic domain for two processes which share a common file system, and the internet domain for
//any two hosts on the Internet. The symbol constant AF_UNIX is used for the former, and
//AF_INET is used for the latter
//第二个参数表示类型,SOCK_STREAM表示TCP,SOCK_DGRAM表示UDP
//这个函数返回an entry into the file descriptor table (i.e. a small integer),this value is used for all
// subsequent references to this socket
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("fd-----> %d\n",fd);
if (fd < 0) {
perror("socket");
return 1;
}
/* Connect to the remote host. */
socketAddr_in.sin_family = AF_INET;
socketAddr_in.sin_port = htons(80);
socketAddr_in.sin_addr = *(struct in_addr*)baiduhost->h_addr;
//connect函数,从进程到内核传递套接字地址结构的函数,第二个参数为socket指针,第三个参数为大小
if (connect(fd, (struct sockaddr*) &socketAddr_in, sizeof(socketAddr_in))) {
perror("connect");
close(fd);
return 1;
}
/* Write the query. */
/* XXX Can send succeed partially? */
//使用send和recv发送和接收数据时,都使用无限循环
cp = query;
remaining = strlen(query);
while (remaining) {
n_written = send(fd, cp, remaining, 0); //send函数,成功则返回实际传送出去的字符数,失败返回-1
if (n_written <= 0) {
perror("send");
return 1;
}
remaining -= n_written; //remaining 不为0表明还没有发送完数据
cp += n_written;
}
/* Get an answer back. */
//将返回结果读入到buf中,利用循环来实现读取所有的数据
while (1) {
ssize_t result = recv(fd, buf, sizeof(buf), 0);
if (result == 0) { //result返回0,表示读入完毕,跳出循环
break;
} else if (result < 0) {
perror("recv");
close(fd);
return 1;
}
fwrite(buf, 1, result, stdout); //写入文件或者标准输出
}
close(fd);
return 0;
}