美文网首页
TCP服务器和客户端的实现

TCP服务器和客户端的实现

作者: 二进制人类 | 来源:发表于2022-09-19 19:45 被阅读0次

流程

服务端

  1. 创建套接字
  2. 设置套接字属性:允许端口被重新使用
  3. 设置主机的IP地址和端口号
  4. 启动服务器监听客户端的请求
  5. 获取请求简历链接

客户端

  1. 创建套接字
  2. 向服务端发送连接请求
  3. 发送数据

相关API

创建socket

#include <sys/types.h>       
#include <sys/socket.h>
/*
参数:
    参数1:domain表示通信域
        AF_UNIX, AF_LOCAL   Local communication              unix(7)     本地域 
        AF_INET             IPv4 Internet protocols          ip(7)       IPV4地址协议族 
        AF_INET6            IPv6 Internet protocols          ipv6(7)     IPV6地址协议族 
    参数2:type表示通信节点的通信方式
        SOCK_STREAM       流式套接字类型    TCP    数据通信方式是以字节流形式传输
        SOCK_DGRAM        数据报套接字类型  UDP    数据通信方式是以数据包形式传输
        SOCK_RAW          原始套接字               可以对底层协议进行修改和访问
    参数3:protocol使用的协议号,在SOCK_RAW的时候修改,在默认情况下使用0;
返回值:成功返回通信节点文件描述符,失败返回-1且修改errno的值。
*/
int socket(int domain, int type, int protocol);

设置套接字属性

#include <sys/types.h>          
#include <sys/socket.h>
/**
 * [setsockopt 设置套接字属性]
 * @param  sockfd  [套接字文件描述符]
 * @param  level   [选项级别,支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6]
 * @param  optname [准备设置的选项]
 * @param  optval  [存放选项待设置的新值]
 * @param  optlen  [optval长度]
 * @return         [无错返回0,否则返回错误代码]
 */
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

设置主机IP和端口

#include <sys/types.h>
#include <sys/socket.h>
/**
 * [bind 绑定端口和IP]
 * @param  sockfd  [套接字文件描述符]
 * @param  addr    [地址端口等结构体]
 * @param  addrlen [结构体长度]
 * @return         [成功返回0,失败返回-1且修改errno的值。]
 */
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

启动服务器监听

#include <sys/types.h>         
#include <sys/socket.h>
/**
 * [listen 启动监听]
 * @param  sockfd  [套接字文件描述符]
 * @param  backlog [表示的是挂起连接请求(客户端发出连接请求,服务器还没有响应)队列的大小。
        不是已经建立连接成功客户端的个数。]
 * @return         [成功返回0,失败返回-1且修改errno的值]
 */
int listen(int sockfd, int backlog);

建立连接

#include <sys/types.h>          
#include <sys/socket.h>
/**
 * [accept 接受建立连接]
 * @param  sockfd  [套接字文件描述符]
 * @param  addr    [是一个结构体指针,指向的空间用来存储返回对端的IP地址和端口信息。]
 * @param  addrlen [addr结构体大小]
 * @return         [成功返回新连接客户端的套接字文件描述符,失败返回-1,且修改errno的值]
 */
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

实例

服务器

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 

int main()
{
    int listenfd;
    int connfd;
    int ret;
    int optval;
    struct sockaddr_in srvaddr;
    struct sockaddr_in cltaddr;
    socklen_t addrlen = sizeof(cltaddr);
    char buf[128];

    /* 1. 创建TCP流式套接字文件 */
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        perror("socket");
        return -1;
    }

    /* 设置套接字允许IP地址和端口被重新设置 */
    optval = 1;/* 允许IP地址和端口被重新设置 */
    ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (ret == -1)
    {
        perror("setsockopt");
        return -1;
    }

    /* 2. 设置服务器主机的IP地址和端口号 */
    srvaddr.sin_family = AF_INET;
    srvaddr.sin_port = htons(8888);
    srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
    if (ret == -1)
    {
        perror("bind");
        return -1;
    }

    /* 3. 启动服务器监听客户端的连接请求 */
    ret = listen(listenfd, 1024);
    if (ret == -1)
    {
        perror("listen");
        return -1;
    }
    printf("listenfd = %d server init success\n", listenfd);

    /* 4. 服务器等待监听客户端的连接请求并建立连接 */
    connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen);
    if (connfd == -1)
    {
        perror("accept");
        return -1;
    }
    printf("connfd = %d client connect success\n", connfd);


    /* 5. 服务循环等待客户端的通信数据,并处理数据 */
    while(1)
    {
        /* 接收客户端的数据请求 */
        memset(buf, 0, sizeof(buf));
        ret = read(connfd, buf, sizeof(buf));
        if (ret == -1)
        {
            perror("read");
            return -1;
        }
        else if (ret == 0)
        {
            /*说明对端(客户端)退出*/
            break;
        }
        //printf("buf : %s\n", buf);
        /* 调用write数据的回写 */
        ret = write(connfd, buf, sizeof(buf));
        if (ret == -1)
        {
            perror("write");
            return -1;
        }
    }
}

客户端

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>

int main()
{
    int ret;
    int sockfd;
    char buf[128];
    struct sockaddr_in srvaddr;

    /* 1. 创建TCP流式套接字文件 */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket");
        return -1;
    }
    /* 2. 向服务器发送连接请求,并建立连接 */
    srvaddr.sin_family = AF_INET;
    srvaddr.sin_port = htons(8888);/* 服务器的端口号 */
    srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");/* 服务器的IP地址 */
    ret = connect(sockfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
    if (ret == -1)
    {
        perror("connect");
        return -1;
    }
    /* 3. 循环向服务器发送数据请求,并接收处理结果*/
    while(1)
    {
        /* 发送数据给服务器 */
        fgets(buf, sizeof(buf), stdin);
        ret = write(sockfd, buf, sizeof(buf));
        if (ret == -1)
        {
            perror("write");
            return -1;
        }

        /* 接收服务器的处理结果 */
        memset(buf, 0, sizeof(buf));
        ret = read(sockfd, buf, sizeof(buf));
        if (ret == -1)
        {
            perror("read");
            return -1;
        }
        else if (ret == 0)
        {
            /* 服务器断开当前客户端的连接 */
            break;
        }

        printf("buf:%s\n", buf);
    }
}

相关文章

网友评论

      本文标题:TCP服务器和客户端的实现

      本文链接:https://www.haomeiwen.com/subject/touvortx.html