基本函数与结构

IPv4套接字结构

套接字结构,定义IP地址与端口号,仅用于IPv4,不适用IPv6

#include <netinet/in.h>
struct sockaddr_in{
    uint8_t sin_len; //本结构长度,16字节
    sa_family_t sin_family; // AF_INET
    in_port_t sin_port; //16位端口号
    struct in_addr sin_addr; //32位IP地址
    char sin_zero[8]; //未使用的字符数组
};
 
//32位IP地址结构,sockaddr_in的第四个成员
struct in_addr{
    in_addr_t s_addr;
};

通用套接字结构

由于IPv4,IPv6,域套接字的结构不一样,为了兼容性于是有了通用套接字结构
sockaddr通常用于函数的参数转换,结构大小随协议的不同而改变,在实际使用时,函数会要求传入一个结构大小的参数

struct sockaddr{
    uint8_t sa_len;
    sa_family_t sa_family;
    char sa_data[14];
};

socket函数

socket函数,用来说明协议和返回一个套接字描述符

#include <sys/socket.h>
int socket(int family, int type, int protocol);

family: AF_INET表示IPv4,AF_INET6表示IPv6,AF_LOCOL表示Unix域协议
type: SOCK_STREAM表示字节流,SOCK_DGRAM表示数据报,另外还有SOCK_RAW和SOCK_SEQPACKET
protocol: 一般填0由系统根据前两个参数自动选择. 可选项有IPPROTO_TCP,IPPROTO_UDP,IPPROTO_SCTP
返回值: 称为套接字描述符,与文件描述符类似

connect函数

客户端使用connect函数向服务端发起连接请求

#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *servaddr, socklen_t addrlen);

sockfd: 由socket函数返回的套接字描述符
servaddr: 需要通用套接字地址,IPv4或IPv6套接字地址都需要在此转换一下,servaddr对应的套接字地址信息是服务器的地址和端口号
addrlen: 前一个参数的长度

bind函数

服务器端绑定端口用

#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);

与connect参数类似,不同的是bind中myaddr的套接字地址信息是本地的地址和端口号

listen函数

服务器端在绑定端口后,listen函数将端口设置为可连接状态,同时listen也可用于设置最多客户端连接数量

int listen(int sockfd,int backlog);

backlog用于设置客户端连接数量上限

accept函数

如果当前没有客户端连接上来,函数使进程投入睡眠.当客户端正确完成连接后,进程被唤醒开始处理事务

#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);

sockfd为socket函数的返回值
cliaddr是一个传出参数,记录着客户端的IP和端口号
addrlen参数既是传入也是传出,函数开始执行时作为传入参数,其值是cliaddr结构的大小,由我们通过sizeof获取,当函数执行完毕时,addrlen被作为传出参数,其值是实际客户端结构的大小
便于理解的例子: nread=read(fd,buff,nleft),我们要从fd中读取nleft个字节到buff中,read函数的返回值是实际读取的字节数,而accept函数相当于把nleft和nread合并在一起,当我们开始read时从nleft得知要读取的字节数,读取完毕后将返回值写到nleft所在的内存上

close函数

关闭套接字描述符

#include <unistd.h>
int close(int sockfd);

转换函数

主机端字节序与网络字节序转换,s表示short,l虽然表示long但只有32位

#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
uint16_t ntohs(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint32_t ntohl(uint32_t host32bitvalue);

IP地址的字符表示与网络字节表示转换

#include <arpa/inet.h>
//老式,用于v4
inet_aton(const char *strptr,struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
 
char *inet_ntoa(struct in_addr inaddr);
 
//新式,兼容v4和v6
int inet_pton(int family,const char *strptr,void *addrptr);
const char *inet_ntop(int family,const void *addrptr,char *strptr,size_t len);

获取套接字ip

#include <sys/socket.h>
int getsockname(int sockfd,struct sockaddr *localaddr,socklen_t *addrlen);
int getpeername(int sockfd,struct sockaddr *peeraddr,socklen_t *addrlen);

getsockname: 获取sockfd套接字本地端的ip地址, 存储在localaddr中, addrlen作输入输出
getpeername: 获取sockfd套接字另一端的ip地址, 后两个参数作用同上

例子1.字节序转换

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
 
/* test host byteorder and net byteorder */
int main(int argc, const char *argv[])
{
    unsigned int num=0x12345678;
    unsigned char *p=(unsigned char *)&num;
    printf("%0x %0x %0x %0x
",p[0],p[1],p[2],p[3]);
    unsigned int x=htonl(num);
    p=(unsigned char *)&x;
    printf("%0x %0x %0x %0x
",p[0],p[1],p[2],p[3]);
 
    char *ipstr="192.168.1.1";
 
    /* old function */
    struct in_addr addr;
    unsigned int netip=inet_addr(ipstr);
    printf("netip=%u
",netip);
    //addr.s_addr=netip;
    inet_aton(ipstr,&addr);
    printf("ipstr=%s
",inet_ntoa(addr));
 
    /* new function */
    struct in_addr addr2;
    inet_pton(AF_INET,ipstr,&addr2);
    printf("netip=%u
",addr.s_addr);
    char ipstrbuf[INET_ADDRSTRLEN];
    inet_ntop(AF_INET,&addr2,ipstrbuf,sizeof(ipstrbuf));
    printf("ipstrbuf=%s
",ipstrbuf);
    return 0;
}

例子2.获取socket连接的本地和对端ip地址及端口

    /* client.c */
    //connect(sockfd,(struct sockaddr *)&servaddr,len);
    struct sockaddr_in localaddr;
    socklen_t len=sizeof(localaddr);
    /* getsockname getpeername 参数均一致,只能换个名字即可 */
    /* server端调用时要放到accept之后 */
    if(getsockname(sockfd,(struct sockaddr *)&localaddr,&len) < 0)
        err_quit("getsockname");
    printf("local addr=%s,local port=%d
",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.sin_port));
原文地址:https://www.cnblogs.com/cfans1993/p/5883366.html