Linux环境编程--网络通信socket编程笔记

一.网络通信模型

 

    TCP/IP:Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。

    OSI/ISO:OSI模型,即开放式通信系统互联参考模型(Open System Interconnection,OSI/RM,Open Systems Interconnection Reference Model),是国际标准化(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。

    TCP/UDP(传输层协议)

    TCP:通过面向连接、端到端和可靠的数据包发送。(通常用来传输需要保密数据)

    UDP:不面向连接、不可靠的数据包发送(通常用来传输大数据)

    IPV4/IPV6:(网络层)

    IPV4:IP地址是32位即,2的32次方

    IPV6:IP地址是64位即,2的64次方

    将IPV4转化用的是NAT(网络地址转换)

    一般操作系统会自动完成传输层、网络层、物理层的衔接

    操作系统五大功能:进程调度(CPU)、内存管理、文件系统(硬盘)、设备管理(外设)、网络管理(计算机网络)

    MAC 地址:物理地址(在物理层定义的)48位,每个网卡都有一个物理地址。前三个为厂商ID,后三个字节为流水号

二.unix网络编程流程

    

三.函数socket()

    int socket(int domain, int type, int protocol);

    创建socket, 返回文件描述符

    domain(域):   AF_INET(IPV4)(机器与机器联系)、AF_INET6(IPV6)、AF_UNIX(命名socket)(进程与进程之相互通信)、AF_UPSPEC

type(类型):   SOCK_DGRAM(数据报文)、 SOCK_RAW(原始报文)、 SOCK_SEQPACKET(带序列的报文)、 SOCK_STREAM(TCP报文)

protocol:   IPPROTO_IP、IPPROTO_IPV6、IPPROTO_ICMP(ping命令,服从ICMP协议)、IPPROTO_RAW、IPPROTO_TCPIPPROTO_UDP

    返回值是 fd(文件描述符)

四.函数bind()

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    将socket和相应的IP地址、端口绑定

     sockfd:   socket()返回的文件描述符

     addr:    绑定的IP和端口

    addrlen:   addr的长度

五.函数ulisten()、函数accept()

    int listen(int sockfd, int backlog);

    开始监听套接字

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    开始等待客户端连过来套接字

    addr 和 addrlen 一般是NULL,他是客户端套接字的标识(包括客户端IP和端口信息等)

注:1.1024以下的端口需要root权限才可以监听,原因是这些端口大部分已经被厂商使用了 

       2.端口号是16位最大值:65535

      3.网络socket数据必须是大端字节序 htons()将小端字节序换成大端字节序 主机到网络转成short(2个字节16个位)

六.函数connect()

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    连接指定的服务器,其中addr指定连接服务器的IP和端口

七.函数shutdown()、函数close()

    int close(int fd);

    关闭socket

    int shutdown(int sockfd, int how);  

    半关闭socket

    how:   SHUT_RD、 SHUT_WR、 SHUT_RDWR  

八.函数select()

    while {     read(fd1, buf, sizeof(buf) );     read(fd2, buf, sizeof(buf) );     read(fd3, buf,sizeof(buf) );   }

    int select(int nfds,     fd_set *readfds,     fd_set *writefds,  fd_set *exceptfds,     struct timeval *timeout);

    集合最大文件描述符 可读的文件描述符集合   可写的文件描述符集合 异常的文件描述符集合   超时时间

    fd_set      rdset, wrset, errset;         int maxfd;

    FD_ZERO(&rdset);  FD_ZERO(&wrset);   FD_ZERO(&errset);

    FD_SET(fd1, &rdset);   FD_SET(fd2, &rdset);  FD_SET(fd3, &rdset);

    FD_SET(fd1, &wrset);  FD_SET(fd3, &errset);

    maxfd = MAX(fd1, fd2);     maxfd = MAX(maxfd, fd3);

    struct timeval tv;      tv.tv_sec = 30;          tv.tv_usec = 0;

    while( (rv=select(maxfd+1, &rdset, &wrset, &errset, &tv) )> 0 )

    //while( (rv=select(maxfd+1, NULL, NULL, NULL, NULL) )> 0 )  不关心可写、出错,一直阻塞不要超时

{

    if (FD_ISSET(fd1, &rdset))       {         read(fd1, buf, sizeof(buf));     }

    if (FD_ISSET(fd2, &rdset))       {         read(fd2, buf, sizeof(buf));     }

    if (FD_ISSET(fd3, &rdset))       {         read(fd3, buf, sizeof(buf));     }

    if (FD_ISSET(fd1, &wrset))      {         write(fd3, buf, sizeof(buf));     }

    if (FD_ISSET(fd3, &errset))      {         printf("fd3 get error");     }  

注:可以用来延时毫秒级select(0,NULL,NULL,NULL,1ms)

 

九.简单的服务器端程序

int main(int argc, char **argv)

{

    int                     listen_fd,  new_fd = -1;

    struct sockaddr_in      serv_addr;             char                    buf[1024];

                              

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);    //IPV4 TCP协议 listen_fd = 3

    memset(&serv_addr, 0, sizeof(serv_addr));    //对地址清零 

    serv_addr.sin_family = AF_INET;        serv_addr.sin_port = htons(8889);        //1

    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);        //2    任何地址即IP

    bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));        //3

    listen(listen_fd, 13);        //13表示最多13个客户端排队

    while(1)     {

        new_fd = accept(listen_fd, NULL, NULL);        //监听客户端信息(IP、端口)

        memset(buf, 0, sizeof(buf));         read(new_fd, buf, sizeof(buf));     printf("read '%s' from client\n", buf);

        write(new_fd, "goodbye", strlen("goodbye"));

        sleep(1);           close(new_fd);

    }

    close(listen_fd);

}

注:1.网络socket数据必须是大端字节序 htons()将小端字节序换成大端字节序 主机到网络转成short(2个字节16个位),网络转换成主机ntohs()

2.主机到网络转成long(4个字节32个位)

3.sockaddr 与前面的 sockaddr_in不同,这里的sockaddr是通用套接字结构体兼容IPV4和IPV6

4.accept()会返回一个新的文件描述符来表示客户端的信息,此时new_fd与客户端就绑定起来(相当于可以通信的文件描述符),并且accept()为阻塞模式

十.客户端程序

int main(int argc, char **argv)

{

    int                     conn_fd = -1;

    struct sockaddr_in      serv_addr;

    char                    buf[1024];

    conn_fd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_port = htons(8889);

    inet_aton( "127.0.0.1", &serv_addr.sin_addr );        //127.0.0.1表示本机器

    connect(conn_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));        //1

    write(conn_fd, "hello", strlen("hello"));

    memset(buf, 0, sizeof(buf));

    read(conn_fd, buf, sizeof(buf));     printf("read '%s' from client\n", buf);

    sleep(1);       close(conn_fd);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值