操作系统——网络编程——socket——TCP/UDP

网络编程

    底层遵循TCP/IP协议,在系统层上以Socket接口方式呈现

    基于TCP协议的网络通信模型:

                服务器                          客户端

            创建socket对象                  创建socket对象

            准备通信地址(端口号+本机ip地址)   准备通信地址(服务器的公网ip)

            绑定socket与通信地址                 ...

            设置监听和排队数量                   ...

            等待客户端连接                   连接服务器

            分配新的socket对象+

            开辟新的进程或者线程服务             ...

            接收请求                          发送请求

            响应请求                          接收相应

            关闭socket                      关闭socket

        使用到的函数:

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

            功能:创建socket对象

            domain:

                AF_INET             基于IPv4地址通信

            type:

                SOCK_STREAM         数据流协议

            protocol:

                特殊通信协议,一般不用,写0即可

            //网络地址结构体类型

                #include <netinet/in.h>

                struct sockaddr_in {

                    __kernel_sa_family_t    sin_family; // AF_INET

                    __be16      sin_port;   //端口号  大端数据

                    struct in_addr  sin_addr;   // IP地址  大端数据

                }

                struct in_addr {

                    __be32  s_addr;

                };  

                大小端数据转换函数:

                #include <arpa/inet.h>

                uint32_t htonl(uint32_t hostlong);

                功能:把4字节的本地字节序转换成网络字节序

                uint16_t htons(uint16_t hostshort);

                功能:把2字节的本地字节序转换成网络字节序

                uint32_t ntohl(uint32_t netlong);

                功能:把4字节的网络字节序转换成本地字节序

                uint16_t ntohs(uint16_t netshort);

                功能:把2字节的网络字节序转换成本地字节序

                ip地址转换函数:

                #include <sys/socket.h>

                #include <netinet/in.h>

                #include <arpa/inet.h>

                in_addr_t inet_addr(const char *cp);

                功能:把字符串格式的点分十进制表示的ip地址转换成整数形式的ip地址(大端)

                char *inet_ntoa(struct in_addr in);

                功能:把整数形式的ip地址转换成字符串格式的点分十进制表示的ip地址



 

                int listen(int sockfd, int backlog);

                功能:监听socket,数据流通信时使用

                sockfd:socket描述符

                backlog:等待连接socket的排队数量,默认最大值128

                返回值:成功返回0,失败返回-1

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

                功能:等待客户端连接

                sockfd:受监听的socket描述符

                addr:获取客户端的地址

                addrlen:既是输入,也是输出

                    1、既告诉accept函数当前计算机地址结构体的字节数

                    2、同时也能获取客户端的地址结构体字节数

                返回值:连接成功返回一个新的连接后的socket描述符,连接失败返回-1

                注意:如果没有连接,则阻塞


 

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

                功能:连接服务器

                sockfd:socket描述符

                addr:服务器的公网ip地址结构体指针

                addrlen:地址结构体的字节数,用于区分sockaddr——un还是sockaddr——in

                返回值:连接成功返回0  失败返回-1

                注意:TCP收发数据可以继续使用read、write

                #include <sys/types.h>

                #include <sys/socket.h>

                ssize_t send(int sockfd, const void *buf, size_t len, int flags);

                功能:TCP协议通信时专用的数据发送函数

                socket:连接成功的socket描述符

                buf:待发送数据的首地址

                len:要发送的字节数

                flags:

                    0   阻塞发送

                    1   不阻塞发送

                返回值:成功发送的字节数

                    -1  出现错误

                    0   连接断开

                #include <sys/types.h>

                #include <sys/socket.h>

                ssize_t recv(int sockfd, void *buf, size_t len, int flags);

                功能:TCP协议通信时专用的接收数据函数

                socket:连接成功的socket描述符

                buf:储存数据缓冲区内存首地址

                len:缓冲区的大小

                flags:

                    0   阻塞发送

                    1   不阻塞发送

                返回值:成功接收的字节数

                    -1  出现错误

                    0   连接断开

下面是TCP的服务端

            TCP_S

            #include <stdio.h>

            #include <stdlib.h>

            #include <string.h>

            #include <unistd.h>

            #include <sys/socket.h>

            #include <netinet/in.h>

            #include <arpa/inet.h>

            #include <sys/types.h>

            typedef struct sockaddr* SP;

            void server_cli(int cli_fd)

            {

                char buf[4096] = {};

                size_t buf_size = sizeof(buf);

                for(;;)

                {

                    //  接收请求

                    int ret = recv(cli_fd,buf,buf_size,0);

                    if(0 == strcmp(buf,"quit") || 0 >= ret)

                    {

                        printf("客户端%d退出!\n",cli_fd);

                        break;

                    }

                    printf("from %d recv:%s bits:%d\n",

                        cli_fd,buf,ret);

                    //  响应请求

                    strcat(buf," from:server");

                    ret = send(cli_fd,buf,strlen(buf)+1,0);

                    if(0 >= ret)

                    {

                        printf("客户端%d退出!\n",cli_fd);

                        break;

                    }

                }

                close(cli_fd);

                exit(0);

            }

            int main(int argc,const char* argv[])

            {

                //  创建socket

                int sockfd = socket(AF_INET,SOCK_STREAM,0);

                if(0 > sockfd)

                {

                    perror("socket");

                    return EXIT_FAILURE;

                }

                //  准备本机通信地址

                struct sockaddr_in addr = {};

                addr.sin_family = AF_INET;

                addr.sin_port = htons(5566);

                //  本机ip

                addr.sin_addr.s_addr = inet_addr("172.16.83.85");

                socklen_t addrlen = sizeof(addr);

               

                //  绑定

                if(bind(sockfd,(SP)&addr,addrlen))

                {

                    perror("bind");

                    return EXIT_FAILURE;

                }

                //  监听

                if(listen(sockfd,5))

                {

                    perror("listen");

                    return EXIT_FAILURE;

                }

                for(;;)

                {

                    //  等待连接

                    struct sockaddr_in cli_addr = {};

                    int cli_fd = accept(sockfd,(SP)&cli_addr,&addrlen);

                    if(0 > cli_fd)

                    {

                        perror("accept");

                        continue;

                    }

                   

                    //  创建进程服务客户端

                    if(0 == fork())

                    {

                        server_cli(cli_fd);

                    }

                }

            }

           

下面是TCP的客户端

                TCP_C

            #include <stdio.h>

            #include <stdlib.h>

            #include <string.h>

            #include <unistd.h>

            #include <sys/socket.h>

            #include <netinet/in.h>

            #include <arpa/inet.h>

            #include <sys/types.h>

            typedef struct sockaddr* SP;

            int main(int argc,const char* argv[])

            {

                //  创建socket

                int sockfd = socket(AF_INET,SOCK_STREAM,0);

                if(0 > sockfd)

                {

                    perror("socket");

                    return EXIT_FAILURE;

                }

                //  准备服务器公网通信地址

                struct sockaddr_in addr = {};

                addr.sin_family = AF_INET;

                addr.sin_port = htons(5566);

                addr.sin_addr.s_addr = inet_addr("47.97.229.46");

                socklen_t addrlen = sizeof(addr);

               

                //  连接服务器

                if(connect(sockfd,(SP)&addr,addrlen))

                {

                    perror("connect");

                    return EXIT_FAILURE;

                }

               

                char buf[4096] = {};

                size_t buf_size = sizeof(buf);

                for(;;)

                {

                    printf(">>>");

                    fgets(buf,buf_size,stdin);

                    //  发送请求

                    int ret = send(sockfd,buf,strlen(buf)+1,0);

                    if(0 >= ret)

                    {

                        printf("服务器正在升级,请稍候再尝试!\n");

                        break;

                    }

                    if(0 == strncmp(buf,"quit",4))

                    {

                        printf("结束通信!\n");

                        break;

                    }

                    //  接收响应

                    ret = recv(sockfd,buf,buf_size,0);

                    if(0 >= ret)

                    {

                        printf("服务器正在升级,请稍候再尝试!\n");

                        break;

                    }

                    printf("recv:%s bits:%d\n",buf,ret);

                }

                close(sockfd);

            }



 

    基于UDP通信协议的网络通信编程模型

                   接收端                         发送端

                创建socket                      创建socket

                准备通信地址                     准备通信地址

                绑定                              ...

                接受请求                          发送请求

                响应请求                          接收响应

                关闭socket                      关闭socket

              UDP使用到的函数:

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

            功能:创建socket对象

            type:

                SOCK_STREAM         数据流协议 UDP

            UDP专属的数据发送接收函数:

            ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

            const struct sockaddr *dest_addr, socklen_t addrlen);

            功能:UPD协议发送数据

            socket:socket描述符

            buf:待发送数据内存的首地址

            len:待发送数据的字节数

            flags:是否阻塞  一般写0阻塞即可

            dest_addr:通信目标的地址

            addrlen:地址结构体的字节数

            返回值:成功发送的字节数

                0   通信关闭

                -1  出现错误


 

            ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

                        struct sockaddr *src_addr, socklen_t *addrlen);

            功能:UPD协议接收数据

            socket:socket描述符

            buf:存储接收数据的缓冲区内存首地址

            len:缓冲区的字节数

            flags:是否阻塞  一般写0阻塞即可

            src_addr:用于存储发送者的地址

            addrlen:既是输入,也是输出

                1、既告诉函数当前src_addr结构体的字节数

                2、同时也能实际接收到发送者的地址结构体字节数

            成功:成功接收到的字节数

                0   通信关闭

                -1  出现错误

           

下面是UDP的服务端

                UDP_S

            #include <stdio.h>

            #include <stdlib.h>

            #include <string.h>

            #include <unistd.h>

            #include <sys/socket.h>

            #include <netinet/in.h>

            #include <arpa/inet.h>

            #include <sys/types.h>

            typedef struct sockaddr* SP;

            int main(int argc,const char* argv[])

            {

                //  创建socket

                int sockfd = socket(AF_INET,SOCK_DGRAM,0);

                if(0 > sockfd)

                {

                    perror("socket");

                    return EXIT_FAILURE;

                }

               

                //  准备本机通信地址

                struct sockaddr_in srv_addr = {},cli_addr = {};

                srv_addr.sin_family = AF_INET;

                srv_addr.sin_port = htons(7788);

                srv_addr.sin_addr.s_addr = inet_addr("172.16.83.85");

                socklen_t addrlen = sizeof(srv_addr);

                //  绑定

                if(bind(sockfd,(SP)&srv_addr,addrlen))

                {

                    perror("bind");

                    return EXIT_FAILURE;

                }

                char buf[4096] = {};

                size_t buf_size = sizeof(buf);

                for(;;)

                {

                    //  接收数据和对方的地址

                    int ret = recvfrom(sockfd,buf,buf_size,0,(SP)&cli_addr,&addrlen);

                    if(0 >= ret)

                    {

                        printf("网络异常,通信结束!");

                        close(sockfd);

                        return EXIT_FAILURE;

                    }

                    printf("from %s recv:[%s] bits:%d\n",

                        inet_ntoa(cli_addr.sin_addr),buf,ret);

                    //  返回响应

                    strcat(buf,"from udpS");

                    ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&cli_addr,addrlen);

                    if(0 >= ret)

                    {

                        printf("对方网络异常!\n");    

                    }

                }

            }  

           下面是UDP的客户端

                UDP_C

            #include <stdio.h>

            #include <stdlib.h>

            #include <string.h>

            #include <unistd.h>

            #include <sys/socket.h>

            #include <netinet/in.h>

            #include <arpa/inet.h>

            #include <sys/types.h>

            typedef struct sockaddr* SP;

            int main(int argc,const char* argv[])

            {

                //  创建socket

                int sockfd = socket(AF_INET,SOCK_DGRAM,0);

                if(0 > sockfd)

                {

                    perror("socket");

                    return EXIT_FAILURE;

                }

               

                //  准备服务器通信地址

                struct sockaddr_in srv_addr = {};

                srv_addr.sin_family = AF_INET;

                srv_addr.sin_port = htons(7788);

                srv_addr.sin_addr.s_addr = inet_addr("47.97.229.46");

                socklen_t addrlen = sizeof(srv_addr);

                char buf[4096] = {};

                size_t buf_size = sizeof(buf);

                for(;;)

                {

                    printf(">>>");

                    scanf("%s",buf);

                    if(0 == strcmp(buf,"quit"))

                    {

                        printf("结束通信!\n");

                        close(sockfd);

                        return EXIT_SUCCESS;

                    }

                    int ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&srv_addr,addrlen);

                    if(0 >= ret)

                    {

                        printf("网络异常!\n");

                        close(sockfd);

                        return EXIT_FAILURE;

                    }

                    //  接收数据和对方的地址

                    ret = recvfrom(sockfd,buf,buf_size,0,(SP)&srv_addr,&addrlen);

                    if(0 >= ret)

                    {

                        printf("网络异常,通信结束!");

                        close(sockfd);

                        return EXIT_FAILURE;

                    }

                    printf("from %s recv:[%s] bits:%d\n",

                        inet_ntoa(srv_addr.sin_addr),buf,ret);

                }

            }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyu1381

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值