非阻塞connect:Web客户程序
一、web.h
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/select.h>
#include <sys/socket.h> #define MAXFILES 20
#define SERV "80" /* port number or service name */
#define MAXLINE 4096 struct file {
char *f_name; /* filename */
char *f_host; /* hostname or IPv4/IPv6 address */
int f_fd; /* descriptor */
int f_flags; /* F_xxx below */
} file[MAXFILES]; #define F_CONNECTING 1 /* connect() in progress */
#define F_READING 2 /* connect() complete; now reading */
#define F_DONE 4 /* all done */ #define GET_CMD "GET %s HTTP/1.0\r\n\r\n" /* globals */
int nconn, nfiles;
int nlefttoconn, nlefttoread;
int maxfd;
fd_set rset, wset; /* function prototypes */
int min(const int, const int);
int tcp_connect(const char *, const char *);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
void err_quit(const char *, ...);
void home_page(const char *, const char *);
void start_connect(struct file *);
void write_get_cmd(struct file *);
ssize_t writen(int, const void *, size_t);
struct addrinfo * host_serv(const char *, const char *, int, int);
二、web.c
#include "web.h" int main(int argc, char **argv)
{
int i, fd, maxnconn;
int flags, error;
char buf[MAXLINE];
fd_set rs, ws;
socklen_t n; if (argc < ) {
err_quit("usage: web <conns> <hostname> <homepage> <file1> ...");
}
maxnconn = atoi(argv[]); nfiles = min(argc - , MAXFILES);
for (i = ; i < nfiles; i++) {
file[i].f_name = argv[i + ];
file[i].f_host = argv[];
file[i].f_flags = ;
}
printf("nfiles = %d\n", nfiles); home_page(argv[], argv[]); FD_ZERO(&rset);
FD_ZERO(&wset);
maxfd = -;
nlefttoread = nfiles;
nlefttoconn = nfiles;
nconn = ; while (nlefttoread > ) {
while (nconn < maxnconn && nlefttoconn > ) {
/* find a file to read */
for (i = ; i < nfiles; i++) {
if (file[i].f_flags == ) {
break;
}
}
if (i == nfiles) {
err_quit("nlefttoconn = %d but nothing found", nlefttoconn);
}
start_connect(&file[i]);
nconn++;
nlefttoconn--;
} rs = rset;
ws = wset;
n = select(maxfd+, &rs, &ws, NULL, NULL); for (i = ; i < nfiles; i++) {
flags = file[i].f_flags;
if (flags == || flags & F_DONE) {
continue;
}
fd = file[i].f_fd;
if (flags & F_CONNECTING &&
(FD_ISSET(fd, &rs) || FD_ISSET(fd, &ws))) {
n = sizeof(error);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n) < ||
error != ) {
err_ret("nonblocking connect failed for %s",
file[i].f_name);
}
/* connection established */
printf("connection established for %s\n", file[i].f_name);
FD_CLR(fd, &wset); /* no more writeability test */
write_get_cmd(&file[i]); /* write() the GET command */ } else if (flags & F_READING && FD_ISSET(fd, &rs)) {
if ( (n = read(fd, buf, sizeof(buf))) == ) {
printf("end-of-file on %s\n", file[i].f_name);
close(fd);
file[i].f_flags = F_DONE; /* clears F_READING */
FD_CLR(fd, &rset);
nconn--;
nlefttoread--;
} else {
printf("read %d bytes from %s\n", n, file[i].f_name);
}
}
}
}
exit();
}
三、home_page.c
#include "web.h" void home_page(const char *host, const char *fname)
{
int fd, n;
char line[MAXLINE]; fd = tcp_connect(host, SERV); /* blocking connect() */ n = snprintf(line, sizeof(line), GET_CMD, fname);
if (writen(fd, line, n) == -) {
err_sys("write error");
} for ( ; ; ) {
if ( (n = read(fd, line, MAXLINE)) == ) {
break; /* server closed connection */
}
printf("read %d bytes of home page\n", n);
/* do whatever with data */
}
printf("end-of-file on home page\n");
close(fd);
}
四、start_connect.c
#include "web.h" void start_connect(struct file *fptr)
{
int fd, flags, n;
struct addrinfo *ai; ai = host_serv(fptr->f_host, SERV, , SOCK_STREAM); fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
fptr->f_fd = fd;
printf("start_connect for %s, fd %d\n", fptr->f_name, fd); /* Set socket nonblocking */
flags = fcntl(fd, F_GETFL, );
fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* Initiate nonblocking connect to the server. */
if ( (n = connect(fd, ai->ai_addr, ai->ai_addrlen)) < ) {
if (errno != EINPROGRESS) {
err_sys("nonblocking connect error");
}
fptr->f_flags = F_CONNECTING;
FD_SET(fd, &rset); /* select for reading and writing */
FD_SET(fd, &wset);
if (fd > maxfd) {
maxfd = fd;
}
} else if (n >= ) { /* connect is already done */
write_get_cmd(fptr); /* write() the GET command */
}
}
五、tcp_connect.c
#include "web.h" int tcp_connect(const char *host, const char *serv)
{
int sockfd, n;
struct addrinfo hints;
struct addrinfo *res, *ressave; bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; if ( (n = getaddrinfo(host, serv, &hints, &res)) != ) {
err_quit("tcp_connect error for %s, %s: %s",
host, serv, gai_strerror(n));
}
ressave = res; do {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < ) {
continue; /* ignore this one */
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == ) {
break; /* success */
}
close(sockfd); /* ignore this one */
} while ( (res = res->ai_next) != NULL); if (res == NULL) { /* errno set from final connect() */
err_sys("tcp_connect error for %s, %s", host, serv);
} freeaddrinfo(ressave); return (sockfd);
}
六、host_serv.c
#include <stddef.h>
#include <netdb.h>
#include <strings.h> struct addrinfo *host_serv(const char *host,
const char *serv, int family, int socktype)
{
int n;
struct addrinfo hints, *res; bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME; /* always return canonical name */
hints.ai_family = family; /* AF_UNSPEC, AF_INET, AF_INET6, etc. */
hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */ if ( (n = getaddrinfo(host, serv, &hints, &res)) != ) {
return(NULL);
} return (res); /* return pointer to first on linked list */
}
七、write_get_cmd.c
#include "web.h" void write_get_cmd(struct file *fptr)
{
int n;
char line[MAXLINE]; n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);
writen(fptr->f_fd, line, n);
printf("wrote %d bytes for %s\n", n, fptr->f_name); fptr->f_flags = F_READING; /* clears F_CONNECTING */ FD_SET(fptr->f_fd, &rset); /* will read server's reply */
if (fptr->f_fd > maxfd) {
maxfd = fptr->f_fd;
}
}
八、writen.c
#include <unistd.h>
#include <errno.h> ssize_t writen(int fd, const void *vptr, size_t n) {
size_t nleft;
ssize_t nwriten;
const char *ptr; ptr = vptr;
nleft = n;
while (nleft > ) {
if ( (nwriten = write(fd, ptr, nleft)) <= ) {
if (nwriten < && errno == EINTR) {
nwriten = ; /* call write() again */
} else {
return (-);
}
}
nleft -= nwriten;
ptr += nwriten;
}
return (n - nwriten);
}
九、others.c
int min(int num1, int num2) {
return (num1<num2?num1:num2);
}
十、error.c
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */ #define MAXLINE 4096 int daemon_proc; /* set nonzero by daemon_init() */ static void err_doit(int, int, const char *, va_list); /* Nonfatal error related to system call
* Print message and return */ void err_ret(const char *fmt, ...) { va_list ap; va_start(ap, fmt);
err_doit(, LOG_INFO, fmt, ap);
va_end(ap);
return;
} /* Fatal error related to system call
* Print message and terminate */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt);
err_doit(, LOG_ERR, fmt, ap);
va_end(ap);
exit();
} /* Fatal error related to system call
* Print message, dump core, and terminate */ void err_dump(const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
err_doit(, LOG_ERR, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(); /* shouldn't get here */
} /* Nonfatal error unrelated to system call
* Print message and return */ void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt);
err_doit(, LOG_INFO, fmt, ap);
va_end(ap);
return;
} /* Fatal error unrelated to system call
* Print message and terminate */ void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt);
err_doit(, LOG_ERR, fmt, ap);
va_end(ap);
exit();
} /* Print message and return to caller
* Caller specifies "errnoflag" and "level" */ static void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n;
char buf[MAXLINE + ]; errno_save = errno; /* value caller might want printed */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = strlen(buf);
if (errnoflag)
snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
strcat(buf, "\n"); if (daemon_proc) {
syslog(level, buf, NULL);
} else {
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);
}
return;
}
十一、Makefile
cccc = gcc
prom = web
deps = web.h
objs = web.o home_page.o tcp_connect.o start_connect.o write_get_cmd.o writen.o others.o error.o host_serv.o $(prom): $(objs)
$(cccc) -o $(prom) $(objs) %.o: %.c $(deps)
$(cccc) -c $< -o $@ clean:
rm -rf $(objs) $(prom)
非阻塞connect:Web客户程序的更多相关文章
- UNIX网络编程——非阻塞connect: Web客户程序
非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...
- UNIX网络编程——非阻塞connect:时间获取客户程序
#include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...
- TCP非阻塞accept和非阻塞connect
http://blog.chinaunix.net/uid-20751538-id-238260.html 非阻塞accept 当一个已完成的连接准备好被accept的时候,select会把监 ...
- 面向连接的socket数据处理过程以及非阻塞connect问题
对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...
- (转)非阻塞Connect对于select时应注意问题
对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...
- linux 客户端 Socket 非阻塞connect编程
开发测试环境:虚拟机CentOS,windows网络调试助手 非阻塞模式有3种用途 1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...
- UNIX网络编程——非阻塞connect
当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...
- 网络编程之非阻塞connect编写
一.connect非阻塞编写 TCP连接的建立涉及到一个三次握手的过程,且socket中connect函数需要一直等到客户接收到对于自己的SYN的ACK为止才返回, 这意味着每 个connect函数总 ...
- TCP之非阻塞connect和accept
套接字的默认状态是阻塞的,这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待响应操作完成,可能阻塞的套接字调用可分为以下四类: (1) 输入操作,包括read,readv,rec ...
- UNIX网络编程-非阻塞connect和非阻塞accept
1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...
随机推荐
- 配置MySQL的数据源
首先查看自己是否有这个驱动 有就进行以下操作,没有那就找下载 安装mysql-for-visualstudio 1)双击 mysql-for-visualstudio-2.0.5.msi 2)点击 ...
- 走进Java Map家族 (1) - HashMap实现原理分析
在Java世界里,有一个古老而神秘的家族——Map.从底层架构到上层应用,他们活跃于世界的每一个角落.但是,每次出现时,他们都戴着一张冷硬的面具(接口),深深隐藏着自己的内心.所有人都认识他们,却并非 ...
- Linux学习历程——Centos 7 账户管理命令(用户篇)useradd usermod userdel
一.命令介绍 useradd 用于创建新的用户 usermod 用于修改用户属性 userdel 用于删除用户 -------------------------------- ...
- 我的Windows日常——你的小电影藏好了吗?
Hello! everybody! 记得大三,第一次上我们某主任的课(我是计算机学部的),某主任上课的第一件事,点名,第二件事,忽悠我们. 具体忽悠步骤如下: 某:”同学们,这里有 ...
- windows10下安装kali子系统
写在前面 为什么我会想到在窗下装一个卡利 作为一个小白,平时做CTF题的时候,有时会用到python2.7环境(比如一些脚本需要,还有窗户下用的SqlMap的话,好像只支持在python2.7,之前被 ...
- Java实现遍历N级树形目录结构
最近挺忙,一直在做项目,然后有个树形目录结构需要返回给前端,这里给大家说一下实现的思路. 具体达到的效果类似: 一级目录A: 二级目录A: 三级目录: 四级目录: 文件.txt 二级目录B: 文件1. ...
- July 11th, 2018. Wednesday, Week 28th.
It is during our darkest moments that we must focus to see the light. 越是在艰难的时候就越要着眼于光明. From Aristol ...
- C#、WPF中如何自定义鼠标样式
需求:在C#中如何自定义鼠标样式?在这里可以分两种情况,一种是在winForm,另一种是在WPF中(注意使用的Cursor对象不一样) 解决办法如下: a.首先针对WinForm中,我们可以采用图标加 ...
- MongoDB系列:三、springboot整合mongoDB的简单demo
在上篇 MongoDB常用操作练习 中,我们在命令提示符窗口使用简单的mongdb的方法操作数据库,实现增删改查及其他的功能.在本篇中,我们将mongodb与spring boot进行整合,也就是在j ...
- kettle变量(param命名参数2)
接arg参数: 通过命令行进行变量赋值和引用 定义跟界面定义相同: 赋值(转换): 运行命令到kettle目录下 pan /file:path "/param:aa="bb&quo ...