函数流程框图:
创建:
int socket(int domain,int type,int protocol);
domain——>协议域:
AF_INET————IPV4。
AF_INET6————IPV6。
AF_LOCAL————Unix域。
type——>类型:
SOCK_STREAM——流式套接字,TCP协议支持该套接字(提供面向连接,可靠的数据传输服务,数据按字节流,按顺序收发,保证在传输过程中无丢失,无冗余)。
SPCK_DGRAM———数据报套接字,UDP协议支持该套接字(提供面向无连接的服务,数据收发无序,不能保证数据的准确到达)。
SOCK_RAM————原始套接字,常用于检测新协议。允许对低于传输层的协议或物理网络直接访问。
protocol——>协议:
0————自动根据type匹配协议。
IPPROTO_TCP。
IPPROTO_UDP。
返回值:
>0时为socket描述符;-1为失败。
关闭:
int close(int fd);
int shutdown(int sockfd,int howto);
sockfd——socket套接字。
howto:
SHUT_RD———值为0;关闭连接的读。
SHUT_WR———值为1;关闭连接的写。
SHUT_RDWR——值为2;连接的读和写都关闭。
绑定:
int bind(int socket,const struct sockaddr* address,socklen_t address_len);
socket—————套接字描述符。
address—————地址和端口号。
address_len———address缓冲区的长度。
返回值——————0为成功;SOCKET_ERROR为失败。
监听:
int listen(int sockfd,int backlog);
socket—————监听的socket描述符。
backlog————排队的最大连接个数。
返回值—————0为成功;-1为失败。
连接:
int connect(int sockfd,const struct sockaddr* addr,socklen_t,addrlen);
sockfd————客户端的socket描述符。
addr—————服务器的socket地址。
addrlen————服务器的socket地址的长度。
返回值—————0为成功l-1为失败。
接受:
int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);
sockfd————服务器的socket描述符,或,监听socket描述符。
addr—————客户端的socket地址。
addrlen————客户端的socket地址长度。
返回值————非-1为连接描述符;-1为失败。
发送:
ssize_t write(int fd,const void* buf,size_t len);
fd————文件描述符。
buf————写入的数据。
len————写入数据长度。
返回值———>0为实际所写的字节数;<0出错。
ssize_t send(int sockfd,const void* buf,size_t len,int flags);
flags——通常为0。
返回值及其他——同上。
ssize_t sendto(int sockdf,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);
dest_addr———目标socket地址。
addrlen————目标socket地址长度。
返回值及其他——同上。
接收:
ssize_t read(int fd,void* buf,size_t len);
buf————读取文件。
返回值——0为读到文件的结束;>0实际所读到的字节数;<0出错。
ssize_t recv(int sockfd,void* buf,size_t len,int flags);
flags——————通常为0。
返回值及其他——同上。
ssize_t recvfrom(int sockdf,void* buf,size_t len,int flags,const struct sockaddr* src_addr,socklen_t addrlen);
结构体:
struct sockaddr:
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
struct sockaddr_in:
struct sockaddr_in{ short sin_family; unsigned short sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; };
struct in_addr:
struct in_addr { in_addr_t s_addr; };
in_addr_t:
typedef unsigned int in_addr_t;
struct sockaddr_in6(IPV6):
struct sockaddr_in6{ //IPv6 为固定的24 字节长度 uint8_t sin6_len; //地址簇类型,为AF_INET6 sa_family_t sin6_family; //16 位端口号,网络字节序 in_port_t sin6_port; //32 位流标签 uint32_t sin6_flowinfo; //128 位IP 地址 struct in6_addr sin6_addr; }
特殊地址设置:
通配地址(0.0.0.0):
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
in6_addr.sin6_addr = in6addr_any;
回环地址(127.0.0.1):
in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
in6_addr.sin6_addr = in6addr_loopback;
广播地址:
in_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
代码:
tcp_cliect:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> void show_info(int connfd){ struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); socklen_t local_addr_len = sizeof(local_addr); getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len); printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port)); struct sockaddr_in peer_addr; bzero(&peer_addr,sizeof(peer_addr)); socklen_t peer_addr_len = sizeof(peer_addr); getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len); printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port)); } int main(int argc,char* argv[]){ if(4 != argc){ printf("usage:%s <ip> <#port> <message>\n",argv[0]); return 1; } int connfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == connfd){ perror("socket err"); return 1; } struct sockaddr_in remote_addr; bzero(&remote_addr,sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_addr.s_addr = inet_addr(argv[1]); remote_addr.sin_port = htons(atoi(argv[2])); if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){ perror("connect err"); return 1; } show_info(connfd); write(connfd,argv[3],strlen(argv[3])+1); printf("client send:%s\n",argv[3]); char buf[BUFSIZ]; bzero(buf,BUFSIZ); if(-1 == read(connfd,buf,BUFSIZ)){ perror("read err"); return 1; } printf("client recv:%s\n",buf); close(connfd); }
tcp_server:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> void show_info(int connfd){ struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); socklen_t local_addr_len = sizeof(local_addr); getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len); printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port)); struct sockaddr_in peer_addr; bzero(&peer_addr,sizeof(peer_addr)); socklen_t peer_addr_len = sizeof(peer_addr); getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len); printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port)); } int main(int argc,char* argv[]){ if(3 != argc){ printf("usage:%s <ip> <#port>\n",argv[0]); return 1; } int listenfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == listenfd){ perror("listenfd open err"); return 1; } printf("socket create OK\n"); int flag = 1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag)); struct sockaddr_in local_addr; bzero(&local_addr,sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = inet_addr(argv[1]); local_addr.sin_port = htons(atoi(argv[2])); if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){ perror("bind err"); return 1; } printf("bind OK\n"); if(-1 == listen(listenfd,10)){ perror("listen err"); return 1; } printf("listen OK\n"); struct sockaddr_in remote_addr; bzero(&remote_addr,sizeof(remote_addr)); socklen_t remote_addr_len = sizeof(remote_addr); int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len); if(-1 == connfd){ perror("accept err"); return 1; } show_info(connfd); printf("accept %s:%d\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port)); char buf[BUFSIZ]; bzero(buf,BUFSIZ); if(-1 == read(connfd,buf,BUFSIZ-1)){ perror("read err"); return 1; } printf("server recv:%s\n",buf); if(-1 == write(connfd,buf,strlen(buf)+1)){ perror("write err"); return 1; } printf("server send:%s\n",buf); close(connfd); close(listenfd); }