Linux C 第十九章 Socket 相关函数
2018-01-20 18:23
323 查看
第十九章 Socket 相关函数
相关头文件: #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> accept : int accept(int s, struct sockaddr* addr, int *addrlen); 接受socket连线 accept()用来接受参数s的socket连线。参数s的socket必需先经bind(),listen()函数处理过,当有连线进来时 accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的 socket参继续使用accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的 地址数据,参数addrlen为sockaddr的结构长度。 成功返回新的socket处理代码,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数addr指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EOPNOTSUPP 指定的socket并非SOCK_STREAM EPERM 防火墙(firewall)拒绝此连线 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 bind :int bind(int sockfd, struct sockaddr* my_addr, int addrlen); 对socket定位 bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain 定义了一个通用的数据结构: struct sockaddr { unsigned short int sa_family; char sa_data[14]; }; sa_family 为调用socket()时的domain参数,即AF_xxxx值。 sa_data 最多使用14个字符长度。 此sockaddr结构会因使用不同的socket domain而有不同结构定义, 如使用AF_INET domain其sockaddr结构定义为: struct socketaddr_in { unsigned short int sin_family; uint16_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }; struct in_addr { uint32_t s_addr; }; sin_family 即为family sin_port 为使用的port编号 sin_addr.s_addr 为IP地址 sin_zero 未使用 参数addrlen为sockaddr的结构长度。 成功则返回0,失败则返回-1,错误代码存于errno中。 EBADF 参数sockfd非合法socket处理代码 EACCESS 权限不足 ENOTSOCK 参数sockfd为一文件描述符,非socket connect :int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 建立socket连线 connect()用来将参数sockfd的socket连至serv_addr指定的网络地址。结构sockaddr请参数bind(). 参数addrlen为sockaddr的结构长度。 成功则返回0,失败则返回-1,错误代码存于errno中。 EBADF 参数sockfd非合法socket处理代码 EFAULT 参数serv_addr指针指向无法存取的存内空间 ENOTSOCK 参数sockfd为一文件描述符,非socket EISCONN 参数sockfd的socket已是连接状态 ECONNERFUSED 连线要求被server拒绝 ENETUNREACH 无法传送数据包至指定的主机 EAFNOSUPPORT sockaddr结构的sa_family不正确 EALERADY socket为不可阻断且先前的连线操作还未完成 /*利用socket 的TCP client 连线TCP server,并将键盘输入的字符串传送给server. * TCP server范例请参考listen() */ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 1234 /*使用的port端口号*/ #define SERVER_IP "127.0.0.1" /*Server IP*/ main() { int s; struct sockaddr_in addr; char buffer[256]; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror("socket:"); exit(1); } /*填写sockaddr_in 结构*/ bzero(*addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = inet_addr(SERVER_IP); /*尝试连接*/ if(connect(s, &addr, sizeof(addr)) < 0){ perror("connect:"); exit(1); } /*接收由server端传来的消息*/ recv(s, buffer, sizeof(buffer), 0); printf("%s\n", buffer); while(1){ bzero(buffer, sizeof(buffer)); /* 从标准输入设备读取字符串*/ read(STDIN_FILENO, buffer, sizeof(buffer)); /*将字符串传给server端*/ if (send(s, buffer, sizeof(buffer), 0) < 0){ perror("send:"); exit(1); } } } endprotoent : void endprotoent(void); 结束网络协议数据的读取。 endprotoent()用来关闭由 getprotoent()所打开的文件。 endservent :void endservent(void); 结束网络服务数据的读取, endservent()用来关闭由 getservent()所打开的文件。 gethostbyaddr :struct hostent * gethostbyaddr(const char* addr, int len, int type); 由IP地址取得网络数据, gethostbyaddr()会返回一个hostent结构, addr可以为IPv4 或IPv6的 IP地址, len addr的长度, type 可以为AF_INET; 成功返回hostent结构指针,若有错误则返回NULL指针。错误原因则存于h_errno变量 HOST_NOT_FOUND 指不到指定的主机 NO_ADDRESS 该主机有名称却无IP地址 NO_RECOVERY 域名服务器有错误发生 TRY_AGAIN 请再调用一次 #include <netdb.h> #include <sys/sockaddr> main(int argc, char *argv[]) { struct hostent *host; if(argc < 2) return; host = gethostbyaddr(argv[1], sizeof(argv[1]), AF_INET); if(host == (struct hostent *)NULL) herror("gethostbyaddr:"); else { printf("name :%s\n", host->h_name); printf("type :%d\n", host->h_addrtype); printf("addr :%s\n", host->h_addr_list[0]); } } gethostbyname :struct hostent *gethostbyname(const char *name); gethostbyname()会返回一个hostent结构,参数name可以为一个主机名称或IPv4/IPv6的IP地址。 结构hostent定义如下: struct hostent{ char *h_name; //正式的主机名称 char **h_aliases; //指向主机名称的其他别名 int h_addrtype; //地址的型态,通常是AF_INET int h_length; //地址的长度 char **h_addr_list; //从域名服务器取得该主机的所有地址 }; 成功返回hostent结构指针,若有错误则返回NULL指针。错误原因则存于h_errno变量 HOST_NOT_FOUND 找不到指定的主机 NO_ADDRESS 该主机有名称却无IP地址 NO_RECOVERY 域名服务器有错误发生 TRY_AGAIN 请再调用一次 /*利用gethostbyname()的简单反查IP程序*/ #include <stdio.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> main(int argc, char **argv) { struct hostent *hp; struct in_addr in; struct sockaddr_in local_addr; if(argc < 2) return; if (!(hp = gethostbyname(argv[1]))){ fprintf(stderr, "Can't resolve host.\n"); exit(1); } memcpy(&local_addr.sin_addr.sa_addr, hp->h_addr, 4); in.s_addr = local_addr.sin_addr.s_addr; printf("Domain Name :%s\n", argv[1]); printf("IP Address :%s\n", inet_ntoa(in)); } getprotobyname :struct protoent *getprotobyname(const char *name); 由网络协议名称取得协议数据 getprotobyname()会返回一个protoent结构,参数name为欲查询的网络协议名称。此函数会从/etc/protocols中 查找符合条件的数据并由结构protoent返回。 成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。 /* 取得icmp协议数据 */ #include <netdb.h> main() { struct protoent *protocol; protocol = getprotobyname("icmp"); printf("protocol name :%s\n", protocol->p_name); printf("protocol number :%d\n", protocol->p_proto); printf("protocol alias :%s\n", protocol->p_aliases[0]); } getprotobynumber :struct protoent *getprotobynumber(int proto); 由网络协议编号取得协议数据 getprotobynumber()会返回一个protoent结构,参数proto为欲查询的网络协议编号。此函数会从/etc/protocols中 查找符合条件的数据并由结构protoent返回。 成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。 /* 取得协议编号0~4的协议数据 */ #include <netdb.h> main() { int number; struct protoent *protocol; for(number=0; i<=4; i++) { protocol = getprotobynumber(number); if (protocol == (struct protoent *)NULL) continue; printf("%2d :%-10s: %-10s\n", protocol->p_proto, protocol->p_name, protocol->p_aliases[0]); } } getprotoent :struct protoent *getprotoent(void); 取得网络协议数据 getprotoent()会打开/etc/protocols,然后读取一行数据后由结构protoent返回。之后再调用此函数则会断续读取 下一项数据,除非已到文件尾时返回NULL指针。 结构protoent定义如下: struct protoent{ char *p_name; /* official protocol name */ char *p_aliases; /* alias list */ int p_proto; /* protocol number */ }; 成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。 /* 取得所有协议数据 */ #include <netdb.h> main() { struct protoent *p; while(p = getprotoent()) { printf("%s %s %d\n", p->p_name, p->p_aliases, p->p_proto); } endprotoent(); } getservbyname :struct servent *getservbyname(const char *name, const char *proto); 依名称取得网络服务的数据 getservbyname()会返回一个servent结构,参数name可以为一个网络服务名称,参数proto则为该服务所使用的协议。 此函数会从/etc/services中查找符合条件的数据并由结构servent返回。 成功返回servent结构指针,若有错误则返回NULL #include <netdb.h> main() { struct servent *s; s = getservbyname("telnet", "tcp"); printf("%s %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto); } getservbyport :struct servent *getservbyport(int port, const char *proto); 依端口号取得网络服务的数据 getservbyport()会返回一个servent结构,参数port可以为一个端口号,参数proto则为该服务所使用的协议。 此函数会从/etc/services中查找符合条件的数据并由结构servent返回。 参数port必须先由htons()转换 成功则返回servent结构指针,若有错误则返回NULL指针。 #include <netdb.h> main() { struct servent *s; s = getservbyport(htons(23), "tcp"); printf("%s %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto); } getservent :struct servent *getservent(void); 取得主机网络服务的数据 getservent()会打开/etc/services,然后读取一行数据后由结构servent返回。之后再调用此函数则会继续读取下 一项数据,除非已到文件结尾时返回NULL指针。 结构servent定义如下: struct servent { char *s_name; //正式的服务名称; char **s_aliases; //别名列表 int s_port; //所使用的端口号; char *s_proto; //所使用的协议名称; }; 成功则返回servent结构指针,若有错误则返回NULL指针。 #include <netdb.h> main() { struct servent *s; while((s = getservent()) != NULL) { printf("%s %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto); } } getsockopt :int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); 取得socket状态 getsockopt()会将参数s所指定的socket状态返回。参数optname代表欲取得何种选项状态,而参数optval则指向欲保存 结果的内存地址,参数optlen则为该空间的大小。 成功返回0,若有错误返回-1,错误原因存于errno中。 EBADF 参数s并非合法的socket处理代码 ENOTSOCK 参数s为一文件描述符,非socket ENOPROTOOPT 参数optname指定的项选不正确 EFAULT 参数optval指针指向无法存取的内存空间 #include <sys/types.h> #include <sys/socket.h> main() { int s, optval, optlen = sizeof(int); if ( (s=socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket:"); getsockopt(s, SOL_SOCKET, SO_TYPE, *optval, &optlen); printf("optval = %d\n", optval); close(s); } herror :void herror(const char *s); 打印出网络错误原因信息字符串 herror()用来将上一个网络函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符会先打印出来。后面再加上 错误的原因字符串。此错误原因系依照全局变量h_errno的值来决定要输出的字符串。 hstrerror :const char *hstrerror(int err); 返回网络错误原因的描术字符 hstrerror()用来依参数err的错误代码来查询socket错误原因的描述字符串,然后将该字符串指针返回。 返回描述错误原因的字符串指针。 /* 显示错误代码0~5的错误原因 */ #include <netdb.h> main() { int i; for (i=0; i<6; i++) { printf("%d :%s\n", i, hstrerror(i)); } } htonl :unsigned long int htonl(unsigned long int hostlong); 将一个32位数主机字节顺序转换成网络字节顺序 htonl()用来将参数指定的32位hostlong转换成网络字节顺序 返回对应的网络字节顺序 htons :unsigned short int htons(unsigned short int hostshort); 将一个16位主机字节顺序转换成网络字节顺序 htonl()用来将参数指定的16位hostshort转换成网络字节顺序 返回对应的网络字节顺序 inet_addr :unsigned long int inet_addr(const char *cp); 将网络地址转换成网络二进制的数字 inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字。网络地址字符串是以数字和点组成的字符串, 例如:"192.168.88.68" 成功返回对应的网络二进制的数字,失败返回-1 inet_aton :int inet_aton(const char *cp, struct in_addr *inp); 将网络地址转换成网络二进制的数字 inet_aton()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字,然后存于参数inp所指的in_addr结构中 结构in_addr定义如下: struct in_addr { unsigned long int s_addr; }; 网络地址字符串是以数字和点组成的字符串,例如:"192.168.88.68" 成功返回非0值,失败返回0 inet_ntoa :char *inet_ntoa(struct in_addr in); 将网络二进制的数字转换成网络地址 inet_ntoa()用来将参数in所指的网络二进制的数字转换成网络地址,然后将指向此网络地址字符串的指针返回。 结构in_addr定义如下: struct in_addr { unsigned long int s_addr; }; 网络地址字符串是以数字和点组成的字符串,例如:"192.168.88.68" 成功返回非0值,失败返回NULL listen :int listen(int s, int backlog); 等待连接 listen()用来等待参数s的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端 将收到ECONNERFUSED的错误。listen()并未开始接受连线,只是设置socket为listen模式,真正接受client端连线的是 accept()。通常listen()会在socket(),bind()之后调用,接着才调用accept()。 listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果scocket为AF_INET则参数backlog最大值可设为128. 成功返回0,发生错误返回-1,错误原因存于errno中。 EBADF 参数sockfd非合法socket处理代码 EACCESS 权限不足 EOPNOTSUPP 指定的socket并未支持listen模式 /*利用socket的TCP server,此程序会接收由TCP client传来的字符串并显示 */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define PORT 1234 //使用的端口号 #define MAXSOCKFD 10 //可同时服务的最大连线数目 main() { int sockfd, newsockfd, is_connected[MAXSOCKFD], fd; struct sockaddr_in addr; int addr_len = sizeof(struct sockaddr_in); fd_set readfds; char buffer[256]; char msg[] = "Welcome to server"; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0) { perror("socket:"); exit(1); } /*填写sockaddr_in结构*/ bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sockfd, &addr, sizeof(addr)) < 0) { perror("bind:"); exit(1); } if(listen(sockfd, 3) < 0) { perror("listen:"); exit(1); } /*清除连线状态旗标*/ for(fd = 0; fd < MAXSOCKFD; fd++) { is_connected[fd] = 0; while(1) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); for(fd = 0; fd < MAXSOCKFD; fd++) { if(is_connected[fd])FD_SET(fd, &readfds); if(!select(MAXSOCKFD, &readfds, NULL, NULL, NULL))continue; /*判断是否有新连线或新信息进来*/ for(fd=0; fd<MAXSOCKFD; fd++) { if(FD_ISSET(fd, &readfds)) { if(sockfd == fd) { /*接收新连线*/ if((newsockfd = accept(sockfd, &addr, &addr_len))<0) { perror("accept:"); } /*将字符串传给client端*/ write(newsockfd, msg, sizeof(msg)); is_connected[newsockfd] = 1; printf("connect from %s\n", inet_ntoa(addr.sin_addr)); } else { /*接收新信息*/ bzero(buffer, sizeof(buffer)); if (read(fd, buffer, sizeof(buffer)) <= 0) { /*连线中断,清除连线状态旗标*/ printf("Connection closed\n"); is_connected[fd] = 0; close(fd); }else{ printf("%s", buffer); } } } } } } } } ntohl :unsigned long int ntohl(unsigned long int netlong); 将32位网络字节顺序转换成主机字节顺序 ntohl()用来将参数指定的32位netlong转换成主机字节顺序。 返回对应的主机字节顺序。 ntohs :unsigned short int ntohs(unsigned short int netshort); 将16位网络字节顺序转换成主机字节顺序 ntohs()用来将参数指定的16位netshort转换成主机字节顺序。 返回对应的主机字节顺序。 recv :int recv(int s, void *buf, int len, unsigned int flags); 经socket接收数据 recv()用来接收远端主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为 可接收数据的最大长度。 参数flags一般设为0,其它定义值如下: MSG_OOB 接收以out-of-band送出的数据 MSG_PEEK 返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据 MSG_WAITALL 强迫接受到len大小的数据后才能返回,除非有错误或信号产生 MSG_NOSIGNAL 此操作不愿被SIGPIPE信号中断 成功返回接收到的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOMEM 系统缓冲内存不足 EINVAL 传给系统调用的参数不正确 recvfrom :int recvfrom(int s, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen); recvfrom()用来接收远程主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为可接收 数据的最大长度。参数flags一般设为0,参数from用来指定欲传送网络地址。参数fromlen为sockaddr的结构长度。 参数flags一般设为0,其它定义值如下: MSG_OOB 接收以out-of-band送出的数据 MSG_PEEK 返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据 MSG_WAITALL 强迫接受到len大小的数据后才能返回,除非有错误或信号产生 MSG_NOSIGNAL 此操作不愿被SIGPIPE信号中断 成功返回接收到的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确 /*利用socket 的UDP client *此程序会连线UDP server, 并将键盘输入的字符串传送给server *UDP server请参考sendto() */ #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 2345 #define SERVER_IP "127.0.0.1" main() { int s, len; struct sockaddr_in addr; int addr_len = sizeof(struct sockaddr_in); char buffer[256]; /*建立socket*/ if((s = socket(AF_INET, SOCK_DGRAM, 0))< 0) { perror("socket:"); exit(1); } /*填写sockaddr_in结构*/ bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = inet_addr(SERVER_IP); while(1) { bzero(buffer, sizeof(buffer)); /*从标准输入设备读取字符串*/ len = read(STDIN_FILENO, buffer, sizeof(buffer)); /*将字符串传送给server端*/ sendto(s, buffer, len, 0, &addr, addr_len); /*接收server返回的字符串*/ len = recvfrom(s, buffer, sizeof(buffer), 0, &addr, &addr_len); printf("receive: %s\n", buffer); } } recvmsg :int recvmsg(int s, struct msghdr *msg, unsigned int flags); 经socket接收数据 recvmsg()用来接收远程主机经指定的socket传来的数据。参数s为已建立好连线的socket,如果利用UDP协议则不需经 过连线操作。参数msg指向欲连线的数据结构内容,参数flags一般为0,详细参考send()。msghdr结构定义参考sendmsg() 成功返回接收到的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确 范例请参考recvfrom(); send :int send(int s, const void *msg, int len, unsigned int flags); 经socket传送数据 send()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket。参数msg指向欲连线的数据内容,参数 len则为数据长度。参数flags一般为0,其它定义值如下: MSG_OOB 传送的数据以out-of-band送出 MSG_DONTROUTE 取消路由表(routing-table)查询 MSG_DONTWAIT 设置为不可阻断运作 MSG_NOSIGNAL 此动作不愿被SIGPIPE信号中断 成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确 范例请参考connect(); sendmsg :int sendmsg(int s, const struct msghdr *msg, unsigned int flags); 经socket传送数据 sendmsg()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket,如果利用UDP协议则不需要经过 连线操作。参数msg指向欲连线的数据内容,参数flags一般为0。 结构msghdr定义如下: struct msghdr { void *msg_name; /*Address to send to/receive from.*/ socklen_t msg_namelen; /*Length of address data.*/ struct iovec *msg_iov; /*Vector of data to send/receive into.*/ size_t msg_iovlen; /*Number of elements in ther vector.*/ void *msg_control; /*Ancillary data.*/ size_t msg_controllen; /*Ancillary data buffer length.*/ int msg_flags; /*Flags on received message.*/ }; 成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确 范例请参考sendto(); sendto : int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); 经socket传送数据 sendto()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket, 如果利用UDP协议则不需经过连线操作。 参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般为0。参数to用来指定欲传送的网络地址,结构sockaddr 请参考bind()。参数tolen为sockaddr的结构长度。 成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述符,非socket EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确 /*利用socket的UDP Server *此程序会接收由UDP client传来的字符串然后再传送回client. *TCP client范例参考recvfrom(); */ #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define PORT 2345 main() { int sockfd , len; struct sockaddr_in addr; int addr_len = sizeof(struct sockaddr_in); char buffer[256]; /*建立socket*/ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket:"); exit(1); } /*填写sockaddr_in结构*/ bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sockfd, &addr, sizeof(addr)) <0) { perror("error:"); exit(1); } while(1) { /*接收client端传来的字符串*/ bzero(buffer, sizeof(buffer)); len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &addr, &addr_len); /*显示client端的网络IP地址*/ printf("receive from %s\n", inet_ntoa(addr.sin_addr)); /*将字符串返回给client端*/ sendto(sockfd, buffer, len, 0, &addr, addr_len); } } setprotoent :void setprotoent(int stayopen); 打开网络协议的数据文件 setprotoent()用来打开/etc/protocols,如果参数stayopen值为1,则接下来的getprotobyname()或getprotobynumber()将 不会自动关闭此文件。 setservent :void setservent(int stayopen); 打开主机网络服务的数据文件 void setservent()用来打开/etc/services,如果参数stayopen值为1,则接下来的getservbyname()或getservbynumber()将 不会自动关闭此文件。 setsockopt :int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); 设置socket状态 setsockopt()用来设置参数s所指定的socket状态。参数level代表欲设置的网络层,一般设成SOL_SOCKET以存取socket层。 参数optname代表欲设置的选项,有下列几种数值: SO_DEBUG 打开或关闭调试模式 SO_REUSEADDR 允许bind()过程中本地地址可重复使用 SO_TYPE 返回socket型态(如:SOCK_STREAM) SO_ERROR 返回socket已发生的错误原因 SO_DONTROUTE 送出的数据包不要利用路由设备来传输 SO_BROADCAST 使用广播方式传送 SO_SNDBUF 设置送出的缓冲区大小 SO_RCVBUF 设置接收的缓冲区大小 SO_KEEPALIVE 定期确定连线是否已终止 SO_OOBINLINE 当接收到OOB(out-of-band)数据时马上送出至标准输入设备 SO_LINGER 确保数据安全且可靠的传送出去 参数optval代表欲设置的值,参数optlen则为optval的长度; 成功则返回0,失败则返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 ENOTSOCK 参数s为一文件描述符,非socket ENOPROTOOPT 参数optname指定的选项不正确 EFAULT 参数optval指针指向无法存取的内存空间 范例请参考getsockopt(); shutdown :int shutdown(int s, int how); 终止socket通信 shutdown()用来终止参数s所指定的socket连线。参数是连线中的socket处理代码,参数how有下列几种情况: how = 0 终止读取操作 how = 1 终止传送操作 how = 2 终止读取及传送操作 成功则返回0,失败则返回-1,错误代码存于errno中。 EBADF 参数s非合法socket处理代码 ENOTSOCK 参数s为一文件描述符,非socket ENOTCONN 参数s指定的socket并未连线 socket :int socket(int domain, int type, int protocol); 建立一个socket通信 socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一个通信端口。参数domain指定使用何 种的地址类型,完整定义在/usr/include/bits/socket.h常用协议如下: PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX进程通信 PF_INET/AF_INET IPv4网络协议 PF_INET6/AF_INET6 IPv6网络协议 PF_IPX/AF_IPX IPX-Novell协议 PF_NETLINK/AF_NETLINK 内核用户接口设备 PF_X25/AF_X25 ITU-T X.25/ISO-8208协议 PF_AX25/AF_AX25 业余无线AX.25协议 PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs PF_APPLETALK/AF_APPLETALK Appletalk(DDP)协议 PF_PACKET/AF_PACKET 初级封包接口 参数type有以下几种取值: SOCK_STREAM 提供双向连续且可靠的数据流,即TCP。支持OOB(out-of-band)机制。在所有数据 传送前必须使用connect()来建立连线状态 SOCK_DGRAM 使用不连续不可靠的数据包连线 SOCK_SEQPACKET 提供连续可靠的数据包连接 SOCK_RAM 提供原始网络协议存取 SOCK_PACKET 提供和网络驱动程序直接通信 参数protocol用来指定socket所使用的传输协议编号,通常此参数不用管,设为0即可 成功则返回socket处理代码,失败则返回-1 EPROTONOSUPPORT 参数domain指定的类型不支持参数type或protocol指定的协议 ENFILE 内核内存不足,无法建立新的socket结构 EMFILE 进程文件表溢出,无法建立新的socket EACCESS 权限不足,无法建立参数type或protocol指定的协议 ENOBUFS/ENOMEM 内存不足。 EINVAL 参数domain/type/protocol不会法 范例请参考connect()
相关文章推荐
- 网络(2):网络配置&socket编程相关的函数选项及异常处理
- C:socket相关的sendto()函数简介
- Socket相关函数定义
- socket套接字的相关函数和理解
- C语言设置和取得socket状态的相关函数用法
- Socket一些函数相关的返回值
- Socket方面的结构体及相关函数
- socket 主机地址相关的函数
- linux c 内存相关函数
- linux socket编程相关函数作用及参数详细分析
- socket相关的函数I/O模型
- socket网络编程的相关函数
- socket相关函数
- Linux C 创建目录函数mkdir相关【转】
- Socket使用相关函数
- Linux Socket 相关函数作用及参数详细分析
- 【Cocos2dx通信(Http&Socket)相关编译到Android细节总结】编译加入curl关联lib与头文件 && 解决pthread的cancel函数NDK不支持,找不到sockaddr_i
- IO特性(1): socket相关的几个高级IO函数(Unix网络编程笔记)
- C语言中socket相关网络编程函数小结
- socket 及其相关函数