zoukankan      html  css  js  c++  java
  • [原创] Linux 网络编程 总结

    1、所用到的头文件:
     

    sys/types.h:数据类型定义

    sys/socket.h:提供socket函数及数据结构

    netinet/in.h:定义数据结构sockaddr_in

    arpa/inet.h:提供IP地址转换函数

    netdb.h:提供设置及获取域名的函数(DNS相关)

    sys/ioctl.h:提供对I/O控制的函数

    sys/poll.h:提供socket等待测试机制的函数


    其他在网络程序中常见的头文件 
    unistd.h:提供通用的文件、目录、程序及进程操作的函数

    errno.h:提供错误号errno的定义,用于错误处理

    fcntl.h:提供对文件控制的函数(控制 socket 是否 blocking)

    time.h:提供有关时间的函数(select 需要用到)

    crypt.h:提供使用DES加密算法的加密函数

    pwd.h:提供对/etc/passwd文件访问的函数

    shadow.h:提供对/etc/shadow文件访问的函数

    pthread.h:提供多线程操作的函数

    signal.h:提供对信号操作的函数

    sys/wait.h、sys/ipc.h、sys/shm.h:提供进程等待、进程间通讯(IPC)及共享内存的函数

     
     
    1、网络地址结构体:
     
    struct sockaddr
    {
        unsigned short sa_family;     // address family, AF_xxx
        char sa_data[14];                  // 14 bytes of protocol address
    };
     
    struct sockaddr_in
    {
        short int sin_family;                 // Address family
        unsigned short int sin_port;     // Port number
        struct in_addr sin_addr;         // Internet address
        unsigned char sin_zero[8];     // Same size as struct sockaddr
    };
     
     
    2、网络字节序转换函数:
     
    htons() – "Host to Network Short"
    htonl() – "Host to Network Long"
    ntohs() – "Network to Host Short"
    ntohl() – "Network to Host Long"
      
     
    3、IP地址转换函数:
    inet_addr()
    ina.sin_addr.s_addr = inet_addr("10.12.110.57");
     
    int inet_aton(const char *cp, struct in_addr *inp);
    注意:返回0为失败!返回非0为成功!
     
    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET; // host byte order
    my_addr.sin_port = htons(MYPORT); // short, network byte order
    inet_aton("10.12.110.57", &(my_addr.sin_addr));
    memset(&(my_addr.sin_zero), ’\0’, 8); // zero the rest of the struct
     
     
    inet_ntoa()
    printf("%s", inet_ntoa(ina.sin_addr));
    返回值保存在一个静态变量中,每次调用这个函数,均会刷新返回值。
     
    4、socket()–Get the File Descriptor!
    int socket(int domain, int type, int protocol);
     
    domain: AF_INET
    type: SOCK_STREAM, SOCK_DGRAM
    protocol: 0
     
    返回:socket 文件描述符,或 -1,错误代码在errno。
     
     
    5、bind()–What port am I on?
    int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
    参数:
    addrlen:sizeof(struct sockaddr)
    返回:错误-1,错误代码在errno
     
    自动获取IP地址:
    my_addr.sin_addr.s_addr = INADDR_ANY
    自动获取端口号:
    my_addr.sin_port = 0
     
     
     
    6、connect()–Hey, you!
    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
    connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
     
    返回:错误-1,错误代码在errno
     
    当用来连接的socket没有进行bind时,会自动将此socket bind到一个任意端口上。
     
     
    7、listen()–Will somebody please call me?
    int listen(int sockfd, int backlog);
    参数:
    sockfd:如果不进行bind,则操作系统会任意将此socket bind到一个任意端口!
    backlog:接入等待队列长度,默认为20
    返回:错误-1,错误代码在errno
     
     
    8、accept()–"Thank you for calling port 3490."
    int accept(int sockfd, void *addr, int *addrlen);
    参数:
    sockfd:用来listen的socket
    addr:用来接收连接方的地址信息
    addrlen:设定为 sizeof(struct sockaddr),期望接收的地址信息长度,如果接收少了的话,accept函数会改变此值。
     
    返回:一个新的socket 描述符!错误返回-1,错误代码在errno。
     
     
    9、send() –Talk to me, baby!
    int send(int sockfd, const void *msg, int len, int flags);
    参数:
    sockfd:socket描述符
    msg:要发送的信息
    len:发送信息的长度
    flags:0
     
    返回:实际发送的长度,错误返回-1,错误代码在errno。
     
    注意:实际发送的长度有可能小于期望发送的长度!需要循环发送。
     
    10、recv()–Talk to me, baby!
    int recv(int sockfd, void *buf, int len, unsigned int flags);
    参数:
    buf:接收缓冲区
    len:接收缓冲区长度
     
    返回:实际接收的长度,错误返回-1,错误代码在errno。返回0,说明对方关闭了链接。
     
    11、sendto() –Talk to me, DGRAM-style
    int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
    参数:
    to:对方的地址和端口。
    tolen:sizeof(struct sockaddr)
     
    返回:实际发送的长度(有可能小于期望发送的长度!),错误返回-1,错误代码在errno。
     
     
     
    12、recvfrom()–Talk to me, DGRAM-style
    int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
    参数:
    from:发送方的地址信息。
    fromlen:期望接收的发送方的地址信息长度(sizeof(struct sockaddr)),如果实际接收比这个值小,则recvfrom函数会更改这个参数。
     
    注意:如果将SOCK_DGRAM类型的socket connect之后,可以使用send(),recv()函数收发数据,函数将自动添加相应的地址信息!但是仍然使用的是UDP协议!
     
     
    13、close() and shutdown()–Get outta my face!
    close(sockfd); 双向关闭一个socket,不能再进行收发操作。
    int shutdown(int sockfd, int how);
    参数:
    how:0不能继续读,1不能继续写,2不能继续读写
    返回:0成功,错误返回-1,错误代码在errno
     
    注意:
    如果使用shutdown在connect之后的SOCK_DGRAM类型的socket上,则会禁止使用send()和recv()进行数据传输。
    shutdown没有真正关闭socket文件标示符,只是改变了可用性。如果需要真正关闭,需要调用close()
     
     
    14、getpeername()–Who are you?
    int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
    得到一个连接后的SOCK_STREAM类型socket对方的地址信息。
     
     
    15、gethostname()–Who am I?
    int gethostname(char *hostname, size_t size);
    返回当前主机的主机名。
     
     
     
    16、DNS
    struct hostent *gethostbyname(const char *name);
     
    数据结构:
    struct hostent
    {
        char *h_name;
        char **h_aliases;
        int h_addrtype;
        int h_length;
        char **h_addr_list;
    };
    #define h_addr h_addr_list[0]
     
    返回:错误返回NULL,错误代码在h_errno
     
     
    17、Blocking
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(sockfd, F_SETFL, O_NONBLOCK);
    这样处理之后的socket在recv() 或者recvfrom()之后不会block,如果没有数据,会返回-1,errorno会被设定为“EWOULDBLOCK”
    注意:这种方式会造成忙等待。
     
    18、select()–Synchronous I/O Multiplexing
    int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    同时监视多组文件描述符,如果有文件描述符可以被(读、写、出现异常),select返回,并且将对应文件描述符组修改为出现时间的文件描述符。通过检测每个文件描述符组,就可以知道出现事件的文件描述符。
     
    参数:
    numfds:应该被设定为最大的文件描述符+1(越是后建立的socket,描述符越大)
    readfds:用来读取的文件描述符组,当不关心时,设置为NULL
    writefds:用来写入的文件描述符组,当不关心时,设置为NULL
    exceptfds:出现异常的文件描述符组,当不关心时,设置为NULL
    timeout:超时时间,当超过这个时间后,select将直接返回。当设定为NULL时,永不超时。
     
    操作fd_set的宏定义:
    FD_ZERO(fd_set *set) – clears a file descriptor set
    FD_SET(int fd, fd_set *set) – adds fd to the set
    FD_CLR(int fd, fd_set *set) – removes fd from the set
    FD_ISSET(int fd, fd_set *set) – tests to see if fd is in the set
     
    拷贝两个fd_set:a = b
     
    时间结构体:
    struct timeval
    {
        int tv_sec; // seconds
        int tv_usec; // microseconds
    };
     
     
    19、循环发送
    int sendall(int s, char *buf, int *len)
    {
        int total = 0; // how many bytes we’ve sent
        int bytesleft = *len; // how many we have left to send
        int n;
        while(total < *len) {
            n = send(s, buf+total, bytesleft, 0);
            if (n == -1) { break; }
            total += n;
            bytesleft -= n;
        }
        *len = total; // return number actually sent here
        return n==-1?-1:0; // return -1 on failure, 0 on success
    }
     
     
  • 相关阅读:
    easyui datagrid 前后台代码
    JVM
    序列化
    Android UI设计
    多线程
    泛型
    字符串
    B+树:MySql数据库索引是如何实现的
    大数据判存算法:海量数据中快速判断某个数据是否存在
    陌生单词
  • 原文地址:https://www.cnblogs.com/icemoon1987/p/2793402.html
Copyright © 2011-2022 走看看