套接字地址结构:
#include<netinet/in.h>
struct in_addr{ #存放ip地址
in_addr_t s_addr; /*32-bit IPv4 address*/
}; /*network byte ordered*/
struct sockaddr_in{ #存放sock地址所有信息,包含ip
unit8_t sin_len; /*length of structure(16)*/
sa_family_t sin_family; /*AF_INET*/
in_port_t sin_port; /*16-bit TCP or UDP port number*/
/*network byte ordered*/
struct in_addr sin_addr; /*32-bit IPv4 address, network byte ordered*/
char sin_zero[8];
- 通用套接字地址结构是为了解决不同协议族之间套接字地址结构不同的问题
struct sockaddr{
unit8_t sa_len; /*address family:AF_xxx value*/
sa_family_t sa_family; /*protocol-specific address*/
char sa_data[14] ;
- 套接字函数都被定义为以指向某个通用套接字地址结构的一个指针作为其参数之一,所以函数的任何调用都要进行强制类型转换,举例如下
struct sockaddr_in server ;
int bind(int, (struct sockaddr *) &server, sizeof(server));
API:
#include <sys/socket.h>
int socket(int family, int type, int protocol);
family:
AF_INET, AF_INET6, AF_LOCAL(AF_UNIX), AF_ROUTE, AF_KEY
type:
SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW
protocol:
IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP, 0(default)
error return -1
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);
success return 0, error return -1
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
success return 0, error return -1
server:
IPV4:
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
IPV6:
struct sockaddr_in6 servaddr;
servaddr.sin6_addr = in6addr_any;
#include <sys/socket.h>
int listen(int sockfd, int backlog);
success return 0, error return -1
convert active-socket to passive-socket
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen);
error return -1
sockfd should be a passive-socket(listened-socket)
#include <unistd.h>
pid_t fork(void);
error return -1
#include <unistd.h>
int execl(const char * pathname, const char * arg0, ... /* (char *)0 */);
int execv(const char * pathname, char * const argv[]);
int execle(const char * pathname, const char * arg0, ...
/* (char *)0, char * const envp[] */);
int execve(const char * pathname, char * const argv[], char * const envp[]);
int execlp(const char * filename, const char * arg0, ... /* (char *)0 */);
int execvp(const char * filename, char * const argv[]);
success no return, error return -1
#include <unistd.h>
int close(int sockfd);
success return 0, error return -1
#include <sys/socket.h>
#取得本地套接字地址
int getsockname(int sockfd, struct sockaddr * localaddr, socklen_t * addrlen);
#取得对方套接字地址
int getpeername(int sockfd, struct sockaddr * peeraddr, socklen_t * addrlen);
success return 0, error return -1
- 经过TCP封装后的数据称为TCP segment,TCP为通信双方维持一个链接,且在内核存储相关数据,这部分数据包括TCP头部信息和TCP内核缓冲区。当应用层调用write进行写数据的时候,数据首先会从用户空间拷贝到与该TCP链接所对应的内核缓冲区中,然后TCP模块调用IP模块进行数据的发送。
- 当应用进程多次执行写操作的时候,TCP把这些数据缓存到本地的TCP缓冲区中,当TCP真正开始发送数据的时候,发送缓冲区中的这些等待发送的数据可能被封装成一个或多个TCPsegment,所以应用进程的写次数和TCP发送的次数没有数量关系。
- 当接受段接收到一个或多个TCP segment后,TCP把他们携带的数据按照TCPsegment的格式进行解析后发到TCP接受缓冲区中,并通知应用进程读数据(怎么通知?)。接受端可以一次性全部读完,也可以读多次,这取决于应用进程缓冲区的大小。
获取套接字的地址信息
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
//返回:若字符串有效则为1,否则为0
in_addr_t inet_addr(const char *strptr); #该函数已经弃用,尽量另外两个
//返回:若字符串有效则为32位二进制网络字节序的IPV4地址,否则为INADDR_None
char *inet_ntoa(struct in_addr inaddr);
//返回:指向一个点分十进制数串的指针
网友评论