一、TCP网络编程

网络编程模型:
C/S模型:客户端服务器模型
优点:
客户端可以缓存一些数据,使用时直接在本地读取,无需每次重新下载;
由于客户端和服务器都是自己开发的,可以自定义协议

缺点:代码开发量大

B/S模型:浏览器服务器模型

(一)流程

网络编程(二)TCP编程-LMLPHP
服务器流程
创建套接字–socket()
填充服务器的网络信息结构体
将套接字与服务器网络信息结构体绑定–bind()
将套接字设置成被动监听状态–listen()
阻塞客户端连接–accept()
收发数据–write()/read()
关闭套接字–close()

客户端流程
创建套接字–socket()
填充服务器的网络信息结构体
与服务器建立连接–connect()
收发数据–write()/read()
关闭套接字–close()

(二)相关函数

1. socket

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
    创建套接字
参数:
    domain:通信域
        AF_UNIX  AF_LOCAL  本地通信使用
        AF_INET            IPV4使用
        AF_INET6          IPV6使用
        AF_PACKET          原始套接字使用
    type:套接字类型
        SOCK_STREAM      TCP使用
        SOCK_DGRAM       UDP使用
    protocol:附加协议 传0 表示没有附加协议
返回值:
    成功  套接字(文件描述符)
    失败  -1  重置错误码

2. bind

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
    将套接字与服务器网络信息结构体绑定
参数:
    sockfd:套接字
    addr:网络信息结构体的首地址
        struct sockaddr {
            sa_family_t sa_family;
            char        sa_data[14];
        }
        //上面的结构体只是用来强转 防止编译警告的 
        //实际使用的是下面的结构体
        struct sockaddr_in {
            sa_family_t    sin_family; /* AF_INET */
            in_port_t      sin_port;   /* 网络字节序的端口号 */
            struct in_addr sin_addr;   /* 网络地址 */
        };
        struct in_addr {
            uint32_t       s_addr;     /* 网络字节序无符号4字节整型的IP地址 */
        };
    addrlen:addr的长度
返回值:
    成功  0
    失败  -1  重置错误码

3. listen

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
    将套接字设置成被动监听状态
参数:
    sockfd:套接字
    backlog:指定半连接队列的最大长度
            一般传 5  10  等都可以 不是 0 就行
            //因为我们实际开发时 一般都是并发服务器 基本能维持半连接队列中没有元素
返回值:
    成功  0
    失败  -1  重置错误码

4. accept

阻塞等待客户端连接

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
    提取半连接队列中的第一个链接,会返回一个新的套接字专门用于和该客户端通信
    如果半连接队列中没有连接请求 accept函数会阻塞
参数:
    sockfd:套接字 必须是已经绑定了本地地址 且置成被动监听状态的
    addr:用于保存客户端的网络信息结构体的缓冲区的首地址 不关心可以传NULL
    addrlen:addr的大小,不关心也可以传NULL
返回值:
    成功  新的套接字用于收发数据
    失败  -1  重置错误码

5. connect

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
    与服务器建立连接
参数:
    sockfd:套接字
    addr:要连接的服务器的网络信息结构体的首地址
    addrlen:addr的长度
返回值:
    成功  0
    失败  -1  重置错误码

一、收发函数

(一)send函数

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
    向套接字上发送一条消息
参数:
    sockfd:套接字
    buf:要发送的数据的首地址
    len:想要发送的字节数
    flags:标志位  0  阻塞   MSG_DONTWAIT 非阻塞
返回值:
    成功 实际发送的字节数
    失败 -1 重置错误码
    如果对方关闭了套接字或者断开连接,第一次send没有任何现象
    但是第二次send会产生一个SIGPIPE
等价关系:
write(sockfd, buff, sizeof(buff));
send(sockfd, buff, sizeof(buff), 0);
sendto(sockfd, buff, sizeof(buff), 0, NULL, 0);

(二)recv函数

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
    在套接字上接收一条消息
参数:
    sockfd:套接字
    buf:用来存放接收到的数据的缓冲区的首地址
    len:想要接收的字节数
    flags:标志位  0  阻塞   MSG_DONTWAIT 非阻塞
返回值:
    成功 实际接收的字节数
    失败 -1 重置错误码
    TCP的套接字,如果对方断开连接或者关闭套接字,recv会返回0
等价关系:
read(sockfd, buff, sizeof(buff));
recv(sockfd, buff, sizeof(buff), 0);
recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);

二、C/S客户端服务器代码

三、TCP粘包问题

服务器程序中禁止使用sleep函数

06-18 02:25