• linux下socket编程


    相关结构

    //下边这两个结构定义在<sys/types.h>里
    //一般的地址结构,只能用于覆盖(把其他地址转换为此类型),且只能引用该地址的sa_family字段
     struct sockaddr
        {
    	unsigned char sa_len;	//total length,整个结构体的长度,旧版本没有
    	unsigned short  sa_family;   //地址族
    	char	sa_data[14];   //地址的值
      
      //TCP/IP使用的地址结构
    struct sockaddr_in
        {
           unsigned char	sin_len;	//total length
           short int                     sin_family;   //地址族,一般为AF_INET(ipv4),ipv6为(AF_INET6)
           unsigned short int      sin_port;      //端口号
           struct in_addr             sin_addr;      //ip地址
           char             sin_zero[8];  //没有使用(设置为0)
        }
    

    相关函数-主调用

    如果函数调用失败,都返回-1,调用失败会在全局变量error里有相应的值
    不涉及到读取、发送的时候,调用正常都返回0

    socket()

    创建套接字

    int socket(int family, int type, int protocol)
    

    family: 协议或地址族,TCP/IP为PF_INET,(ipv6为PF_INET6),也可以使用AF_INET
    type: 套接字类型

    • 流式套接字:SCOK_STREAM, TCP
    • 数据报套接字:SOCK_DGRAM,UDP
    • 原始套接字:SOCK_RAW,没有经过处理的IP数据包,可以根据自己程序的要求进行封装

    protocol:用来指定socket所使用的传输协议编号,通常设为0即可。

    调用成功返回描述符

    connect()

    为套接字指明远程端点的地址。为TCP时,connect使用三次握手建立连接;为UDP时,connect仅指明远程端点,但是不向他发送任何数据

    int connect(int sock, struct sockaddr *serv_addr, int addrlen)
    

    sock: 目的服务器的socket描述符
    serv_addr:包含目的机器ip地址和端口号的指针
    addrlen:sizeof(struct sockaddr)
    调用成功返回0

    send()/write() -TCP

    linux下可以使用write(),将报文传递给目标主机

    (int sock, char* msg, int msglen, int flags);
    

    flags:控制bit,指明是否接受带外数据和是否预览报文,一般为0

    write(int sock, char* buf,  int buflen)
    

    buf:含有数据缓存的地址
    buflen:buf中的字节数
    这两个函数调用成功时都返回传送的字节数

    recv()/read() -TCP

    从套接字中接收数据

    nt recv(int sock, char* buf, int len, int flags)
    

    buf:存放数据的缓存地址
    len:缓存的长度
    flags:控制bit,指明是否接受带外数据和是否预览报文一般为0

    read(int sock, char* buf,  int buflen)
    

    调用成功都返回读取的字节数

    sendto() -UDP

    从一个结构中获取目的地址,然后发送报文

    int sendto(int sock, char *msg, int msglen, int flags, const struct sockaddr* to, int* tolen);
    

    tolen:地址结构的字节长度
    成功时,返回已发送的字节数

    recvfrom() -UDP

    从套接字获取下一个传入报文,并记录发送者的地址

     int recvfrom(int sock, char* buf, int buflen, int flags, struct sockaddr* from, int* fromlen)
    

    fromlen:缓存的长度,返回时为发送者地址的大小。
    成功调用时,返回报文中的字节数

    bind()

    主要由服务器使用,指明本地ip地址和协议端口号

     int bind(int sock, struct sockaddr *localaddr, int addrlen)
    

    成功时返回0

    listen() -TCP

    服务器调用,使套接字处于被动状态(准备接受传入请求)

    int listen ( sock,queuelen)
    

    queuelen:传入链接请求的队列大小(通常最大不超过5)

    accept() -TCP

    bind->listen->accept,从队列中取走下一个链接请求(或者一直在那里等待下一个连接请求到来),为请求创建新套接字,并返回新套接字描述符。

    int accept(int sock, struct sockaddr * addr, int* addrlen)
    

    addrlen:初始指明为addr的大小,调用返回时为存储在addr中的字节数

    close()

    终止通信,删除套接字,任何正在套接字上等待被读取的数据都将被抛弃。
    linux使用了引用计数机制,可以多个进程共享一个套接字。close每被调用一次,引用计数减1,引用计数为0时才释放。

    int close(int sock)
    

    成功时返回0

    shutdown()

    部分关闭连接

    int shutdown(int sock,int direction )
    

    direction:0,终止进一步输入;1,终止进一步输出;2,终止输入和输出

    辅助函数

    整数转换

    TCP/IP协议首部使用的二进制采用网络字节顺序(表示整数时,最高字节在前)
    为了机器和网络字节顺序兼容,应当始终调用转换函数

    htons(host to network short)
    ntohs
    htonl
    ntohl
    

    地址转换inet_addr

    接受字符串(点分十进制),返回等价二进制表示的地址

    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    

    查找域名对应ip地址gethostbyname

    接收ASCII字符串域名,返回hostent结构,定义在<netdb.h>

    struct hostent
    {
    	char*	 h_name,	//正式主机名
    	char**	 h_aliases,	//其他别名列表
    	int		 h_addrtype,	//地址类型
    	int		 h_length,	//地址长度
    	char**	 h_addr_list	//一般主机可以有多个ip地址,h_addr_list用来
    保存多个ip地址
    }
    #define h_addr h_addr_list[0]	//为了与早期的版本兼容
    

    由服务名字得到熟知端口getservbyname

    成功则返回一个servent结构指针,发生差错就返回空指针,结构定义在<netdb.h>

    servent* getservbyname(char* name, char* proto)
    

    struct servent
    {
    char* s_name; //正式服务名
    char** s_aliases; //其他别名列表
    int s_port; //该服务使用的端口
    char *s_proto; //服务器所用的协议
    };

    
    ### 根据协议名找到该协议的正式整数值getprotobyname(char* name)
    成功就返回protoent结构指针,结构定义在`<netdb.h>`中
    ```C
    struct protoent
    {
    	char*		p_name;	//协议正式名
    	char**	p_aliases;	//协议的别名列表
    	int			p_proto;		//正式协议名
    }
    

    获取主机名字gethostname

    以字符串形式返回主机名

    int gethostname(char* name, namelen)
    

    name:放置名字的字符数组的地址

    获取远程端点地址getpeername

    需要已经建立链接

    int getpeername(int sock, sockaddr* remaddr, int* addrlen)
    

    remaddr:含有对端地址的sockaddr指针
    addrlen:调用前为第二个参数的长度,调用后为远程端点地址的实际长度

    设置/查看套接字参数

    getsockopt()
    setsockopt()
    

    相关头文件

    参考:socket编程需要哪些头文件

    <sys/types.h>           //primitive system data types(包含很多类型重定义,如pid_t、int8_t等) 
    <sys/socket.h>         //与套接字相关的函数声明和结构体定义,如socket()、bind()、connect()及struct sockaddr的定义等
    //上边两个sock调用必须包含
    <netinet/in.h>          //某些结构体声明、宏定义,如struct sockaddr_in、struct inaddr 、PROTO_ICMP、INADDR_ANY等
    <sys/types.h>           //primitive system data types(包含很多类型重定义,如pid_t、int8_t等) 
    <sys/socket.h>         //与套接字相关的函数声明和结构体定义,如socket()、bind()、connect()及struct sockaddr的定义等
    <sys/ioctl.h>             //I/O控制操作相关的函数声明,如ioctl()
    <stdlib.h>                   //某些结构体定义和宏定义,如EXIT_FAILURE、EXIT_SUCCESS等
    <netdb.h>                  //某些结构体定义、宏定义和函数声明,如struct hostent、struct servent、gethostbyname()、gethostbyaddr()、herror()等
    <arpa/inet.h>           //某些函数声明,如inet_ntop()、inet_ntoa()等
    <netinet/in.h>          //某些结构体声明、宏定义,如struct sockaddr_in、PROTO_ICMP、INADDR_ANY等
    
  • 相关阅读:
    C#11 特性的早期预览
    Eclipse加速启动
    Summary of CRM 2011 plugin
    centos7上利用snap安装nextcloud,并实现在线编辑
    windows上常用命令
    PYMOL显示底物周围surface
    桥接模式
    建造者模式
    模板方法模式
    适配器模式
  • 原文地址:https://www.cnblogs.com/jcuan/p/6009620.html
Copyright © 2020-2023  润新知