曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 10755|回复: 0
打印 上一主题 下一主题

connect() 返回的 EINPROGRESS 错误

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2012-12-1 13:25:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在以非阻塞方式 connect() 时,返回的结果如果是 -1 ,并且错误号为 EINPROGRESS ,那么表示连接还在进行并处理中(IN PROGRESS),而不是真的发生了错误。

下面用一个实例来演示如何观察到返回 EINPROGRESS 的情况。

服务器端代码:
[C++] 纯文本查看 复制代码
#include <stdio.h>                                                                                                                                                    
#include <stdlib.h>                                                                                                                                                   
#include <string.h>                                                                                                                                                   
#include <errno.h>                                                                                                                                                    
#include <netinet/in.h>                                                                                                                                               
#include <arpa/inet.h>                                                                                                                                                
#include <sys/types.h>                                                                                                                                                
#include <sys/socket.h>                                                                                                                                               
 
void str_echo(int sockfd)
{
        int error;
        ssize_t n;
        char buf[1024];
 
again:
        while ( (n = read(sockfd, buf, 1024)) > 0)
                write(sockfd, buf, n);  /* Dend back to client */
 
        if (n < 0 && errno == EINTR)
                goto again;
        else if (n < 0) {
                fprintf (stderr, "Read error");
                exit (EXIT_FAILURE);
        }
}
 
int main(int argc, char **argv)
{
        int listenfd, connfd;
        int clilen;
        pid_t childpid;
 
        struct sockaddr_in servaddr, cliaddr;
 
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
 
        bzero(&servaddr, sizeof(servaddr));
 
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(2013);
        inet_aton("192.168.1.106", &servaddr.sin_addr);
 
        bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 
        listen(listenfd, 1);
 
        for (; ;) {
                clilen = sizeof(cliaddr);
                connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
                if ( (childpid = fork()) == 0) {
                        close(listenfd);
                        str_echo(connfd);
                        exit(0);
                }
                close(connfd);  /* parent closes connected socket */
        }
}

服务器端监绑定在 192.168.1.106,并监听在 2013 端口,当客户端连接上时,读取客户算发来的信息,然后回射(echo)给客户端。

客户端代码:
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
 
#define MAXLINE 1024
 
static int      read_cnt;
static char     *read_ptr;
static char     read_buf[MAXLINE];
 
static ssize_t
my_read(int fd, char *ptr)
{
 
        if (read_cnt <= 0) {
again:
                if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                        if (errno == EINTR)
                                goto again;
                        return(-1);
                } else if (read_cnt == 0)
                        return(0);
                read_ptr = read_buf;
        }
 
        read_cnt--;
        *ptr = *read_ptr++;
        return(1);
}
 
ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
        ssize_t n, rc;
        char    c, *ptr;
 
        ptr = vptr;
        for (n = 1; n < maxlen; n++) {
                if ( (rc = my_read(fd, &c)) == 1) {
                        *ptr++ = c;
                        if (c == '\n')
                                break;  /* newline is stored, like fgets() */
                } else if (rc == 0) {
                        *ptr = 0;
                        return(n - 1);  /* EOF, n - 1 bytes were read */
                } else
                        return(-1);             /* error, errno set by read() */
        }
 
        *ptr = 0;       /* null terminate like fgets() */
        return(n);
}
 
ssize_t
readlinebuf(void **vptrptr)
{
        if (read_cnt)
                *vptrptr = read_ptr;
        return(read_cnt);
}
/* end readline */
 
ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
        ssize_t         n;
 
        if ( (n = readline(fd, ptr, maxlen)) < 0) {
                printf("readline error");
                exit(EXIT_FAILURE);
        }
        return(n);
}
 
void
Fputs(const char *ptr, FILE *stream)
{
        if (fputs(ptr, stream) == EOF) {
                perror("fputs error");
                exit(EXIT_FAILURE);
        }
}
 
void str_cli(FILE *fp, int sockfd)
{
        char sendline[MAXLINE], recvline[MAXLINE];
 
        while (fgets(sendline, MAXLINE, fp) != NULL) {
                write(sockfd, sendline, strlen(sendline));
                
                if (Readline(sockfd, recvline, MAXLINE) == 0) {
                        printf ("str_cli: server terminated prematurely");
                        exit(EXIT_FAILURE);
                }
 
                Fputs(recvline, stdout);
        }
}
 
int main(int argc, char **argv)
{
        int sockfd;
        struct sockaddr_in servaddr;
 
        if (argc != 2) {
                printf ("usage: tcpcli <IP>");
                exit(EXIT_FAILURE);
        }
 
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
        bzero(&servaddr, sizeof(servaddr));
 
        servaddr.sin_family = AF_INET;
 
        inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
 
        servaddr.sin_port = htons(2013);


        int arg;
        if ( (arg = fcntl(sockfd, F_GETFL, NULL)) < 0) {
                fprintf(stderr, "Error fcntl(..., F_GETFL) (%S)\n", strerror(errno));
                exit(EXIT_FAILURE);
        }
        arg |= O_NONBLOCK;         /*设置为非阻塞模式*/
        if (fcntl(sockfd, F_SETFL, arg) < 0) {
                fprintf(stderr, "Error fcntl(..., F_SETFL) (%S)\n", strerror(errno));
                exit(EXIT_FAILURE);
        }


        int conret;
        fd_set myset;
        struct timeval tv;
        int valopt;
        int len;


        conret = connect(sockfd+1, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (conret < 0) {
                if (errno == EINPROGRESS) {
                        fprintf(stderr, "EINPROGRESS in connect() - selecting\n"); 
                        do {
                                tv.tv_sec = 15;         /* 15 秒等待*/
                                tv.tv_usec = 0; 
                                FD_ZERO(&myset); 
                                FD_SET(sockfd, &myset); 
                                conret = select(sockfd+1, NULL, &myset, NULL, &tv); 
                                if (conret < 0 && errno != EINTR) { 
                                        fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
                                        exit(0); 
                                } 
                                else if (conret > 0) { 
                                        // Socket selected for write 
                                        len = sizeof(int); 
                                        if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len) < 0) { 
                                                fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); 
                                                exit(0); 
                                        } 
                                        // Check the value returned... 
                                        if (valopt) { 
                                                fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); 
                                                exit(0); 
                                        } 
                                        break;
                                }
                                else { 
                                        fprintf(stderr, "Timeout in select() - Cancelling!\n"); 
                                        exit(0); 
                                } 
                        } while(1);
                }
                else { 
                        fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
                        exit(0); 
                } 


        }
        // Set to blocking mode again... 
        if( (arg = fcntl(sockfd, F_GETFL, NULL)) < 0) { 
                fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno)); 
                exit(0); 
        } 
/*再次设置为阻塞模式*/
        arg &= (~O_NONBLOCK); 


        if( fcntl(sockfd, F_SETFL, arg) < 0) { 
                fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno)); 
                exit(0); 
        } 


        str_cli(stdin, sockfd);
 
        exit(0);
}

当使用该客户端连接服务器后,由于客户端设置了非阻塞模式,因此在调用 connect() 时,它会马上返回(此时三次握手还在进行中,也就是连接还在处理(IN PROGRESS)),并且返回的错误号为 EINPROGRESS 。

实际上,连接客户端的代码并不需要像上面那样复杂,关键点就是为客户端设置非阻塞模式。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-28 16:50 , Processed in 0.063516 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表