#include <sys/types.h>;
#include <sys/socket.h>;
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
在Linux中的socket编程中,建立网络连接是通过connect函数来完成的,函数原型为:
int connect (int sockfd, struct sockaddr * serv_addr, int addrlen)
- sockfd:该参数是通过调用socket()函数来获得socket的文件描述符并传入该位置。
- serv_addr:该参数是可传入的实际结构体为sockaddr_in和sockadd_in6
- sockaddr_in:该结构体存有将要connect的ipv6的网络地址以及端口和协议族
- sockaddr_in6:该结构体存有将要connect的ipv6的网络地址以及端口和协议族
- addrlen: 为传入参数sockaddr结构体的大小,该参数实际应该是一个传出参数。
阻塞模式下connect的返回值和参数设置
- 首先,阻塞和非阻塞不是connect函数的属性。而是通过socket的函数获取的文件描述符所指向的抽象文件的属性。
- 所以需要通过操作socket获取的文件描述符fd(file descriptor)来对其设置为非阻塞,默认情况下,socket文件的属性为阻塞的。
接下来是获取一个阻塞的socket文件描述符
//这里以ipv6的connect连接为例,ipv4可自行百度 int fd = socket(AF_INET6,SOCK_STREAM,0); //AF_INET:指定为ipv6协议族,SOCK_STREAM:面向流的连接,第三个为0就好,该参数是指定具体协议 //由于默认的socket就是阻塞的,所以可以直接将该获取的fd加入到connect的第一个参数中。即完成了第一个参数的设置
//通过一个ipv6的地址字符串和端口获取一个sockaddr_in6 struct sockaddr_in6 addr6; //定义一个sockaddr_in6 addr6.sin6_family = AF_INET6; //指定该sockaddr_in6的协议为ipv6协议 addr6.sin6_port = htons(80); //指定连接的端口,htons()函数是将一个本地字节序的short转为网络字节序的short inet_pton(AF_INET6, "::1", &addr6.sin6_addr); //指定连接的ipv6地址,inet_pton是将ipv6的地址字符串转为网络字节序传输的字符串 //这样就完成了connect的第二个参数的设置 //获取sockaddr_in6的长度 int len = sizeof(sockaddr_in6); //即完成了第三个参数的设置 //调用connect函数进行连接,即完成了整个过程: 连接成功flag返回0,连接失败flag返回-1 int flag = connect(fd,&addr6,len);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- flag返回0时,表明该连接已经成功建立。
- flag返回-1时,表明该连接发生了错误,即没有成功建立连接。
- 并会将发生的错误记录在一个全局变量errno中,其中errno的取值有:
- errno:
- 并会将发生的错误记录在一个全局变量errno中,其中errno的取值有:
注:inet_pton和socket都有可能调用失败,从而需要对其返回值进行相应的错误处理
非阻塞下connect的返回值和参数设置
对于非阻塞的connect的连接,其不会在调用connect的时候进行阻塞,而是立即返回。如果返回0,说明调用connect的时候还没来得及让connect返回便已经建立了连接;而如果返回-1,errno会记录一个错误码,如果该错误码为EINPROGRESS。则说明该连接还正在建立,并不能说明该连接出错。一个非阻塞connect的简单测试。
int flag;
int fd = socket(AF_INET,SOCK_STREAM,0);
flag = fcntl(connect_fd,F_GETFL,0); //获取文件描述符的属性
fcntl(connect_fd, F_SETFL, flag|O_NONBLOCK); //将文件描述符的属性设置为非阻塞
struct sockaddr_in addr={0};
addr.sin_family= AF_INET;
addr.sin_port = htons(80);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
for(;;){
flag = connect(fd,&addr,len); //fd被设置成了非阻塞的文件描述符
if(flag == 0){
printf("connect success!\n");
break;
}else{
if(errno != EINPROGRESS){
printf("connect error!"
"errno:%d\n",errno);
break;
}else{
printf("connection is being established\n")
sleep(1);
continue;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
通常如果connect函数可以最终被调用成功会打印"connection is being established"和"connect success!"。
注意:fcntl函数对文件描述符进行设置和获取的时候需要对其返回值做校验
</div>