在linux的网络编程中经常会使用非阻塞模式的socket。在阻塞模式中,对于调用connect时是阻塞的,只有当socket连接建立起来或者连接出错是connect才返回。然而在阻塞模式中connect会立即返回,至于返回后的socket句柄是否是已经建立好可用的,它是不管的。这个就需要程序员自己写代码来判断,尤其是在做多个并发连接的筛选是尤为重要。然而一般的做法是用接口函数getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);的optval的值来判断,若optval为0则认为socket连接已经建立。
然而我最近写的代码却否定了这一种用法代码如下:
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define OUT(str) do{cout<<str<<endl;}while(0)
#define TEST do{printf("line:%d\n",__LINE__);}while(0)
using namespace std;
static int CreateScok(const char * ip){
struct sockaddr_in serv_addr;
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(443);
serv_addr.sin_addr.s_addr=inet_addr(ip);
bzero(&(serv_addr.sin_zero),8);
SSL_CTX *ctx;
SSL *ssl;
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx= SSL_CTX_new(SSLv23_client_method());
if(ctx == NULL) {
return -1;
}
int sockfd;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
OUT("socket create error");
return -1;
}
int flags=fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flags|O_NONBLOCK);
int n=connect(sockfd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
sleep(2);
if(n<0){
if(errno !=EINPROGRESS){
perror(strerror(errno));
return -1;
}else{
OUT(ip);
OUT("EINPROGRESS");
}
}else{
OUT(ip);
}
ssl= SSL_new(ctx);
if(SSL_set_fd(ssl, sockfd) == 0){
return -1;
}
SSL_set_connect_state(ssl);
if(n==0){
OUT("connect sucess immediately");
return sockfd;
}
return sockfd;
}
int main(){
ifstream ipin("./iplist.txt");
string line;
while(getline(ipin,line)){
int sock=CreateScok(line.c_str());
if(sock==-1){
OUT("connect error");
return 0;
}else{
int ret,error=1;
socklen_t len;
len=sizeof(error);
OUT("fd:");
OUT(sock);
sleep(3);
ret=getsockopt(sock,SOL_SOCKET,SO_ERROR,&error,&len);
if(error == 0){
OUT("SUCESS");
}
OUT("\n\n");
}
//close(sock);
}
return 0;
}
当我获得正在运行的该程序的进程号并查看它的所有的fd状态时发现在程序中通过getsockopt检验的fd的状态依然是SYN_SENT。有些不太明白,希望各位大牛不吝赐教。
联系方式:zhaosendong@hotmail.com