常州网站建设cz35,计算机哪个专业最吃香而且最简单,长沙购物网站建设,wordpress批量换网址Socket 是网络协议栈暴露给编程人员的 API#xff0c;相比复杂的计算机网络协议#xff0c;API 对关键操作和配置数据进行了抽象#xff0c;简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍#xff0c;从而更好的理解 socket 编程。… Socket 是网络协议栈暴露给编程人员的 API相比复杂的计算机网络协议API 对关键操作和配置数据进行了抽象简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍从而更好的理解 socket 编程。 connect connect() 遵循 POSIX.1 - 2008 1.库
标准 c 库libc, -lc
2.头文件
sys/socket.h
3.接口定义 int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
4.接口描述 connect() 系统调用在 sockfd 指定的 socket 上连接 addr 指定的地址addrlen 参数指定了 addr 的大小addr 地址格式取决于 socket 的地址空间可以参考 socket(2)。 如果 socket 是 SOCK_DGRAM 类型那么 addr 是发送报文的默认地址也是唯一接收报文的地址。如果 socket 类型是 SOCK_STREAM 或者 SOCK_SEQPACKET那么这个调用就是尝试和绑定了 addr 地址的 socket 建立连接。 一些协议套接字比如 UNIX 流套接字只能成功连接一次。 一些协议套接字比如 UNIX TCP 套接字和网络数据报套接字可以多次 connect() 来修改连接。 一些协议套接字比如 UNIX TCP 套接字和网络数据报套接字可以通过将 sockaddr 的 sa_family 设置为 AF_UNSPEC 来消除连接之后 socket 就可以连接到其他地址了。AF_UNSPEC 在 Linux 2.2 之后支持。
5.返回值 如果连接或者绑定成功那么返回 0。 发生错误时返回 -1并设置errno 来指示错误类型。 错误值定义如下这里指示普通 socket 的错误还可能存在 domain-specific 错误码
EACCESUNIX 域套接字通过路径名唯一标识并且是套接字文件是没有写权限的路径中任何一级的搜索权限也是没有的可以参考 path_resolution(7)EACCES/EPERM用户尝试连接到一个广播地址却没有设置套接字的广播标记或者请求被防火墙规则拦截了EACCES如果开启了 SELinux 策略也可能会导致连接被拒绝比如策略规定 HTTP 代理只能连接到 HTTP 服务器关联的端口而 HTTP 代理却连接了其他端口EADDRINUSE本地地址已经在用了EADDRNOTAVAIL网络域套接字sockfd 指定的套接字没有绑定到地址并且在尝试将其绑定到临时端口时临时端口用尽了EAFNOSUPPORT地址家族不正确EAGAIN对于非阻塞的 UNIX 域套接字套接字是非阻塞的连接无法立即完成。对于其他套接字家族这个错误标识路由缓存没有足够的条目了EALREADY套接字是非阻塞的并且之前的连接尝试还没有完成EBADFsockfd 不是一个打开的文件描述符ECONNREFUSEDconnect() 操作的流套接字发现没有人在监听对应的远程地址EFAULT套接字结构地址超出用户地址空间EINPROGRESS套接字是非阻塞的连接不能立即完成。UNIX 域套接字会返回 EAGAIN。可以通过 select(2) 或者 poll(2) 查看套接字的可写事件来确定连接完成。select(2) 指示可写后使用 getsockopt(2) 来读取 SOL_SOCKET 级的 SO_ERROR 选项来确定连接完全成功SO_ERROR 为 0或者未成功SO_ERROR 为这里列出来的普通错误。EINTR系统调用被信号打断EISCONN套接字已经连接ENETUNREACH网络不可达ENOTSOCK文件描述符并没有指向一个套接字EPROTOTYPE该套接字不支持指定的通信协议。这个错误可能在出现在连接一个 UNIX 域报文套接字到一个流套接字ETIMEDOUT连接超时。可能是服务器太忙了以至于无法接收新的连接。注意当服务器开启 syncookies 时IP 套接字的超时可能会非常长。
6.注意 如果 connect() 失败那么套接字的状态是未知的。一个易于移植的程序应该关闭该套接字应该再创建一个新套接字重新连接。
7.代码 这里我们展示下 select() 的用法示例来将最近几篇内容串起来
#include stdio.h
#include stdlib.h
#include sys/ioctl.h
#include sys/socket.h
#include sys/time.h
#include netinet/in.h
#include errno.h#define SERVER_PORT 12345#define TRUE 1
#define FALSE 0main (int argc, char *argv[])
{int i, len, rc, on 1;int listen_sd, max_sd, new_sd;int desc_ready, end_server FALSE;int close_conn;char buffer[80];struct sockaddr_in6 addr;struct timeval timeout;struct fd_set master_set, working_set;/*************************************************************//* Create an AF_INET6 stream socket to receive incoming *//* connections on *//*************************************************************/listen_sd socket(AF_INET6, SOCK_STREAM, 0);if (listen_sd 0){perror(socket() failed);exit(-1);}/*************************************************************//* Allow socket descriptor to be reuseable *//*************************************************************/rc setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,(char *)on, sizeof(on));if (rc 0){perror(setsockopt() failed);close(listen_sd);exit(-1);}/*************************************************************//* Set socket to be nonblocking. All of the sockets for *//* the incoming connections will also be nonblocking since *//* they will inherit that state from the listening socket. *//*************************************************************/rc ioctl(listen_sd, FIONBIO, (char *)on);if (rc 0){perror(ioctl() failed);close(listen_sd);exit(-1);}/*************************************************************//* Bind the socket *//*************************************************************/memset(addr, 0, sizeof(addr));addr.sin6_family AF_INET6;memcpy(addr.sin6_addr, in6addr_any, sizeof(in6addr_any));addr.sin6_port htons(SERVER_PORT);rc bind(listen_sd,(struct sockaddr *)addr, sizeof(addr));if (rc 0){perror(bind() failed);close(listen_sd);exit(-1);}/*************************************************************//* Set the listen back log *//*************************************************************/rc listen(listen_sd, 32);if (rc 0){perror(listen() failed);close(listen_sd);exit(-1);}/*************************************************************//* Initialize the master fd_set *//*************************************************************/FD_ZERO(master_set);max_sd listen_sd;FD_SET(listen_sd, master_set);/*************************************************************//* Initialize the timeval struct to 3 minutes. If no *//* activity after 3 minutes this program will end. *//*************************************************************/timeout.tv_sec 3 * 60;timeout.tv_usec 0;/*************************************************************//* Loop waiting for incoming connects or for incoming data *//* on any of the connected sockets. *//*************************************************************/do{/**********************************************************//* Copy the master fd_set over to the working fd_set. *//**********************************************************/memcpy(working_set, master_set, sizeof(master_set));/**********************************************************//* Call select() and wait 3 minutes for it to complete. *//**********************************************************/printf(Waiting on select()...\n);rc select(max_sd 1, working_set, NULL, NULL, timeout);/**********************************************************//* Check to see if the select call failed. *//**********************************************************/if (rc 0){perror( select() failed);break;}/**********************************************************//* Check to see if the 3 minute time out expired. *//**********************************************************/if (rc 0){printf( select() timed out. End program.\n);break;}/**********************************************************//* One or more descriptors are readable. Need to *//* determine which ones they are. *//**********************************************************/desc_ready rc;for (i0; i max_sd desc_ready 0; i){/*******************************************************//* Check to see if this descriptor is ready *//*******************************************************/if (FD_ISSET(i, working_set)){/****************************************************//* A descriptor was found that was readable - one *//* less has to be looked for. This is being done *//* so that we can stop looking at the working set *//* once we have found all of the descriptors that *//* were ready. *//****************************************************/desc_ready - 1;/****************************************************//* Check to see if this is the listening socket *//****************************************************/if (i listen_sd){printf( Listening socket is readable\n);/*************************************************//* Accept all incoming connections that are *//* queued up on the listening socket before we *//* loop back and call select again. *//*************************************************/do{/**********************************************//* Accept each incoming connection. If *//* accept fails with EWOULDBLOCK, then we *//* have accepted all of them. Any other *//* failure on accept will cause us to end the *//* server. *//**********************************************/new_sd accept(listen_sd, NULL, NULL);if (new_sd 0){if (errno ! EWOULDBLOCK){perror( accept() failed);end_server TRUE;}break;}/**********************************************//* Add the new incoming connection to the *//* master read set *//**********************************************/printf( New incoming connection - %d\n, new_sd);FD_SET(new_sd, master_set);if (new_sd max_sd)max_sd new_sd;/**********************************************//* Loop back up and accept another incoming *//* connection *//**********************************************/} while (new_sd ! -1);}/****************************************************//* This is not the listening socket, therefore an *//* existing connection must be readable *//****************************************************/else{printf( Descriptor %d is readable\n, i);close_conn FALSE;/*************************************************//* Receive all incoming data on this socket *//* before we loop back and call select again. *//*************************************************/do{/**********************************************//* Receive data on this connection until the *//* recv fails with EWOULDBLOCK. If any other *//* failure occurs, we will close the *//* connection. *//**********************************************/rc recv(i, buffer, sizeof(buffer), 0);if (rc 0){if (errno ! EWOULDBLOCK){perror( recv() failed);close_conn TRUE;}break;}/**********************************************//* Check to see if the connection has been *//* closed by the client *//**********************************************/if (rc 0){printf( Connection closed\n);close_conn TRUE;break;}/**********************************************//* Data was received *//**********************************************/len rc;printf( %d bytes received\n, len);/**********************************************//* Echo the data back to the client *//**********************************************/rc send(i, buffer, len, 0);if (rc 0){perror( send() failed);close_conn TRUE;break;}} while (TRUE);/*************************************************//* If the close_conn flag was turned on, we need *//* to clean up this active connection. This *//* clean up process includes removing the *//* descriptor from the master set and *//* determining the new maximum descriptor value *//* based on the bits that are still turned on in *//* the master set. *//*************************************************/if (close_conn){close(i);FD_CLR(i, master_set);if (i max_sd){while (FD_ISSET(max_sd, master_set) FALSE)max_sd - 1;}}} /* End of existing connection is readable */} /* End of if (FD_ISSET(i, working_set)) */} /* End of loop through selectable descriptors */} while (end_server FALSE);/*************************************************************//* Clean up all of the sockets that are open *//*************************************************************/for (i0; i max_sd; i){if (FD_ISSET(i, master_set))close(i);}
}