网站建设公司 温州,wordpress设置伪静态,制作网页用的最多的图像文件格式,方城微网站建设1、什么是socket 套接字 socke套接字是一个编程的接口 (网络编程的接口)、是一种特殊的文件描述符 (read/write)#xff0c;不局限于TCP/IP 。socket是独立于具体协议的网络编程接口这个接口是位于 应用层和传输层之间 。 类型#xff1a; (1)流式套接字 SOCK_ST… 1、什么是socket 套接字 socke套接字是一个编程的接口 (网络编程的接口)、是一种特殊的文件描述符 (read/write)不局限于TCP/IP 。socket是独立于具体协议的网络编程接口这个接口是位于 应用层和传输层之间 。 类型 (1)流式套接字 SOCK_STREAM 面向字节流针对于传输层协议为TCP的应用 (2)数据报套接字 SOCK_DGRAM 面向数据报针对于传输层协议为UDP的应用 (3)原始套接字 SOCK_RAW 程序之间对ip层进行访问跳过了传输层
2、基于TCP套接字的编程流程 Server ----- 服务器 socket ----- 创建套接字 bind (服务器的ip和端口) ------ 绑定服务器ip与端口 listen ---- 监听 accept ----- 接受连接请求 read/write ------- 读写 close ------ 关闭 Client ------- 客户端 socket 设置服务器的ip和端口 connect ------ 发出连接请求 write/read close 3、socket套接字的接口函数 1创建一个套接字 socket NAME socket - create an endpoint for communication SYNOPSIS #include sys/types.h /* See NOTES */ #include sys/socket.h int socket(int domain, int type, int protocol); 功能创建一个套接字 参数 domain协议族 socket不局限于TCP/IP它还可以指定其他的通信协议 AF_UNIX, AF_LOCAL Local communication unix(7) AF_INET IPv4 Internet protocols ip(7) AF_INET6 IPv6 Internet protocols ... type指定要创建的套接字类型 SOCK_STREAM 流式套接字 --- TCP SOCK_DGRAM 数据报套接字 --- UDP SOCK_RAW 原始套接字 ... protocol协议指定具体的应用层的协议 一般为 0 不知名的私有协议 返回值 成功返回一个套接字描述符 (0) 失败返回-1同时errno被设置 例子 // 创建一个TCP流式套接字int sock_fd socket( AF_INET, SOCK_STREAM, 0 ); if( sock_fd -1 ){perror(socket error );return -1;}printf(sock_fd %d\n, sock_fd ); 2 bind 绑定服务器的ip和端口 NAME bind - bind a name to a socket SYNOPSIS #include sys/types.h /* See NOTES */ #include sys/socket.h int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能把一个地址绑定到套接字上 参数 sockfd指定要绑定的套接字描述符 addr指向包含地址信息的 struct sockaddr 结构体的指针 addrlen指定要绑定的地址结构体的长度单位字节 返回值 成功返回0 失败返回-1同时errno被设置 (2.1)网络地址结构体 (ip端口) socket接口可以用于 以太网(ipv4)也可以用于ipv6.... 不同的协议族它们的地址是不一样的通用的地址结构体 所有的socket函数接口的 地址参数的类型都是 struct sockaddr {} struct sockaddr { sa_family_t sa_family; //协议族 char sa_data[14]; //指定网络协议地址 } Internet协议地址结构体 man 7 ip 进行查看struct sockaddr_in {sa_family_t sin_family; /* 协议族 in_port_t sin_port; /* 端口号 (网络字节序)struct in_addr sin_addr; /* ip地址};/* Internet address. */struct in_addr {uint32_t s_addr; /* ip地址(整数形式) }; (2.2)网络字节序 不同类型CPU的主机中内存存储多字节整数序列 有两种方式 大端模式 低地址存放数据的高位高地址存放数据的低位 和阅读习惯一致 小端模式 低地址存放数据的低位高地址存放数据的高位 和阅读习惯相反 网络字节序 采用的是 大端模式 网络传输的数据必须按照网络字节序 注意 大部分的主机上当应用程序将多字节整数传递给socket之前需要转换成网络字节序当应用程序从socket上获取多字节整数时需要转换成主机字节序 。 ps. 网络字节序的转换函数 h host 主机字节序 n network 网络字节序 l long 32bits s short 16bits NAME htonl, htons, ntohl, ntohs - convert values between host and network byte order SYNOPSIS #include arpa/inet.h uint32_t htonl(uint32_t hostlong); 功能把一个32bits的整数的主机字节序 转换成 网络字节序 参数 hostlong指定要转换的32bits整数 返回值 返回转换之后的结果 uint16_t htons(uint16_t hostshort); 功能把一个16bits的整数的主机字节序 转换成 网络字节序 uint32_t ntohl(uint32_t netlong); 功能把一个32bits的整数的网络字节序 转换成 主机字节序 uint16_t ntohs(uint16_t netshort); 功能把一个16bits的整数的网络字节序 转换成 主机字节序 (2.3)ipv4地址之间的转换函数 NAME inet_aton, inet_addr, inet_network, inet_ntoa - Internet address manipulation routines SYNOPSIS #include sys/socket.h #include netinet/in.h #include arpa/inet.h int inet_aton(const char *cp, struct in_addr *inp); 功能把 ip地址(点分十进制字符串) 转换成 struct in_addr结构体类型 参数 cp指定要转换的字符串 inp指向 struct in_addr 结构体的指针 返回值 成功返回1 失败返回0同时设置errno in_addr_t inet_addr(const char *cp); 功能把 ip地址(点分十进制字符串) 转换成 32bits整数 (网络字节序) in_addr_t inet_network(const char *cp); 功能把 ip地址(点分十进制字符串) 转换成 32bits整数 (主机字节序) 因此还需要使用 htonl() 进行转换 char *inet_ntoa(struct in_addr in); 功能把 struct in_addr 结构体类型 转换成 ip地址(点分十进制字符串)
例子 //设置服务器的ip和端口struct sockaddr_in server_addr; server_addr.sin_family AF_INET; //协议族 server_addr.sin_port htons( 6666 ); //端口号 ( 网络字节序 )inet_aton( 172.4.0.244, server_addr.sin_addr ); //ip地址 //server_addr.sin_addr.s_addr htonl( inet_network( 172.4.0.244 ) );//server_addr.sin_addr.s_addr inet_addr( 172.4.0.244 );//server_addr.sin_addr.s_addr htonl( INADDR_ANY ); // INADDR_ANY 是一个宏表示任何地址 0.0.0.0 // 一个监听地址表示服务器愿意接收来自任何客户端的连接请求 //绑定 int re bind( sock_fd, (struct sockaddr *)server_addr, sizeof(server_addr) );if( re -1 ){perror(bind error );return -1;}printf(bind success\n); 3 listen 监听 NAME listen - listen for connections on a socket SYNOPSIS #include sys/types.h /* See NOTES */ #include sys/socket.h int listen(int sockfd, int backlog); 功能监听套接字上的连接请求 参数 sockfd指定要监听的套接字描述符 backlog指定最大连接请求的数量 返回值 成功返回0 失败返回-1同时errno被设置 4 accept 接收连接请求 NAME accept - accept a connection on a socket SYNOPSIS #include sys/types.h /* See NOTES */ #include sys/socket.h int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 功能等待一个新的连接用户接受一个来自客户端的连接请求 参数 sockfd指定要接收连接的套接字描述符 addr指向 struct sockaddr 结构体的指针用于返回客户端的地址信息(ip端口) addrlen指向 socklen_t 类型的指针用于指定 addr 结构体的长度 在调用时addrlen保存addr指向空间的最大的长度 在函数返回时addrlen保存实际返回的地址长度 返回值 成功返回一个套接字描述符 后续与客户端发生通信都是使用这个套接字描述符 失败返回-1同时errno被设置
struct sockaddr_in client_addr; //保存客户端的ip端口 socklen_t len sizeof( client_addr );//接受连接int client_sock accept( sock_fd, (struct sockaddr *)client_addr, len );if( client_sock -1 ){perror(accept error );return -1;}printf(client ip %s\n, inet_ntoa( client_addr.sin_addr ) ); 5通信 发送/接收数据 (5.1)发送数据 write / send / sento 这三个函数TCP都可以用但是UDP只能用sendto NAME send, sendto - send a message on a socket SYNOPSIS #include sys/types.h #include sys/socket.h ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 功能发送数据到套接字上 参数 sockfd指定要发送数据的套接字描述符 buf指针指向的空间用来保存要发送的数据 len指定要发送的数据的长度单位字节 flags指定发送标志 0 阻塞模式 MSG_DONTWAIT 非阻塞模式 dest_addr地址结构体指针指定接收方的地址UDP一定要指定TCP可以不指定 addrlen接收方地址结构体的长度单位字节 返回值 成功返回实际发送的字节数 失败返回-1同时errno被设置 (5.2)接收数据 read / recv / recvfrom 这三个函数TCP都可以用但是UDP只能用recvfrom NAME recv, recvfrom - receive a message from a socket SYNOPSIS #include sys/types.h #include sys/socket.h ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 功能从套接字上接收数据 参数 sockfd指定要接收数据的套接字描述符 buf指针指向的空间用来保存接收到的数据 len指定接收的数据的最大长度单位字节 flags指定接收标志 0 阻塞模式 MSG_DONTWAIT 非阻塞模式 src_addr地址结构体指针用于保存发送方的地址UDP一定要指定TCP可以不指定 addrlen地址结构体的长度单位字节 返回值 成功返回实际接收的字节数 失败返回-1同时errno被设置 6关闭套接字 close / shutdown NAME shutdown - shut down part of a full-duplex connection SYNOPSIS #include sys/socket.h int shutdown(int sockfd, int how); 功能关闭指定的套接字 参数 sockfd指定要关闭的套接字描述符 how指定关闭的方式 SHUT_RD 关闭读方向 SHUT_WR 关闭写方向 SHUT_RDWR 关闭读写方向 close( sockfd ) 返回值 成功返回0 失败返回-1同时errno被设置 7connect 连接服务器 NAME connect - initiate a connection on a socket SYNOPSIS #include sys/types.h /* See NOTES */ #include sys/socket.h int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能连接服务器 参数 sockfd指定客户端的套接字描述符 addr地址结构体指针指定要连接的那个服务器的地址ip端口 addrlen地址结构体的长度单位字节 返回值 成功返回0 失败返回-1同时errno被设置
总结示例 利用TCP 写一个网络应用程序的服务器用来接收数据 客户端 用来发送数据 tcp_server.c int main( int argc, char * argv[] ) {//1.创建套接字 socket int server_sock socket( AF_INET, SOCK_STREAM, 0 );if( server_sock -1 ){perror(socket server error );return -1;}printf(server_sock %d\n, server_sock );//2.绑定服务器的ip和端口 bind (服务器的ip和端口)struct sockaddr_in server_addr; server_addr.sin_family AF_INET; //协议族 server_addr.sin_port htons( atoi(argv[2]) ); //端口号 ( 网络字节序 )inet_aton( argv[1] , server_addr.sin_addr ); //ip地址 int re bind( server_sock, (struct sockaddr *)server_addr, sizeof(server_addr) );if( re -1 ){perror(bind server error );close( server_sock );return -1;}printf(bind success! \n); //3.监听 listen re listen( server_sock, 5 );if( re -1 ){perror(listen server error );close( server_sock );return -1;}printf(listen success! \n); //4.接受连接请求 accept struct sockaddr_in client_addr; //保存客户端的ip端口 socklen_t len sizeof( client_addr );int client_sock accept( server_sock, (struct sockaddr *)client_addr, len );if( client_sock -1 ){perror(accept server error );close( server_sock );return -1;}printf(accept success! client_sock %d\n, client_sock );printf(client ip %s\n, inet_ntoa( client_addr.sin_addr ) );//5.通信 recv/sendwhile(1){//接收数据 char buf[128] {0};re recv( client_sock, buf, sizeof(buf), 0 );if( re 0 ){printf(recv %s\n, buf );}else {perror(recv server error );break;}//人为定义退出条件if( buf[0] # ){break;}} //6.关闭套接字 closeclose( server_sock );}tcp_client.c int main( int argc, char * argv[] ){//1.创建套接字 socket int client_sock socket( AF_INET, SOCK_STREAM, 0 );if( client_sock -1 ){ perror(socket client error );return -1;}printf(client_sock %d\n, client_sock );//2.设置服务器的ip和端口,连接服务器 connect struct sockaddr_in server_addr; server_addr.sin_family AF_INET; //协议族 server_addr.sin_port htons( atoi(argv[2]) ); //端口号 ( 网络字节序 )inet_aton( argv[1] , server_addr.sin_addr ); //ip地址 int re connect( client_sock, (struct sockaddr *)server_addr, sizeof(server_addr) );if( re -1 ){perror(connect client error );close( client_sock );return -1;}//3.通信 send/recv while(1){//发送数据 char buf[128] {0};printf(input data: );fgets( buf, sizeof(buf), stdin );re send( client_sock, buf, strlen(buf), 0 );if( re -1 ){perror(send client error );break;}//人为定义退出条件if( buf[0] # ){break;}}//4.关闭套接字 closeclose( client_sock );}