zoukankan      html  css  js  c++  java
  • macos下简单的socket服务器+客户端

    TCP客户端服务器编程模型:

    服务器:

    1. 调用socket函数创建套接字
    2. 调用bind绑定本地IP和端口
    3. 调用listen启动监听(准备好接收客户端链接的队列)
    4. 调用accept从已连接队列中提取第一个连接。(如果没有,会阻塞。)
    5. 调用I/O函数(read/write)与客户端通讯
    6. 调用close关闭套接字。(多个套接字)

    客户端:

    1. 调用socket创建套接字
    2. 调用connect连接服务器
    3. 调用I/O函数(read/write)与服务器通讯
    4. 调用close关闭套接字

    Linux下和Mac下代码一样的,可能有头文件不太一样,用man命令进去查看即可。

    功能:

    1. 客户端连到服务器,服务器打印连接的客户端IP和端口,返回给客户端当前服务器时间。
    2. 服务器加了一个信号捕获函数,ctrl+c停止服务器进程。
    3. 如果不写客户端,使用telnet 127.0.0.1 8888 依然可以收到服务器返回的时间字符串。

    服务器代码 time_tcp_server.c:

    #include <sys/socket.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <time.h>
    #include <string.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    
    #define SERVER_PORT 8888
    #define LISTEN_QUEUE_SISE 10
    
    int socketfd;
    
    void signal_handler(int signo)
    {
        printf("this serveice close
    ");
        close(socketfd);
        exit(1);
    }
    
    void out_clientinfo(const struct sockaddr_in* outsockaddr)
    {
        char ipstr[16];
        memset(ipstr, 0, sizeof(ipstr));
        // 将地址从网络字节序转换为点分十进制
        inet_ntop(AF_INET, &outsockaddr->sin_addr.s_addr, ipstr, sizeof(ipstr));
    
        printf("Connected by %s(%d)
    ", ipstr, ntohs(outsockaddr->sin_port));
    }
    
    void dosomething(int fd)
    {
        //获取系统当前时间
        long t = time(0);
        char* times = ctime(&t);
        size_t size = strlen(times)*sizeof(char);
        //将时间写回到客户端
        if(write(fd, times, size) != size)
        {
            perror("write to client error");
        }
    }
    
    
    int main(int argc, char const *argv[])
    {
        if (signal(SIGINT, signal_handler) == SIG_ERR)
        {
            perror("signal error");
            exit(1);
        }
    
        // 1 sokect
        // AF_INET ipv4
        // SOCK_STREAM tcp
        if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("socket error");
            exit(1);
        }
    
        // 2 bind 绑定本地地址和端口
        struct sockaddr_in serveraddr;
        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;//ipv4
        serveraddr.sin_port = htons(SERVER_PORT); //端口
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);//响应任意网卡的请求
        if(bind(socketfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
        {
            perror("bind error");
            exit(1);
        }
    
        // 3 listen 启动监听 通知系统接受来自客户端的连接 准备好连接队列
        if(listen(socketfd, LISTEN_QUEUE_SISE) < 0)
        {
            perror("listen error");
            exit(1);
        }
        struct sockaddr_in clientaddr;
        socklen_t clientaddr_len = sizeof(clientaddr);
        while(1)
        {    
            // 4 accept 从队列拿出第一个
            // clientaddr获取客户端的地址信息,是传出参数
            int clientfd = accept(socketfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
            if (clientfd  < 0)
            {
                perror("accept error");
                continue;
            }
            // 5 read/write
            out_clientinfo(&clientaddr);
            dosomething(clientfd);
    
            // 6 close
            close(clientfd);
        }
        
        // 6 close
        return 0;
    }

    客户端代码time_tcp_client:

    #include <sys/socket.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <netdb.h>
    
    #define SERVER_PORT 8888
    #define SERVER_IP 127.0.0.1
    
    int main(int argc, char const *argv[])
    {
        //1 创建socket
    
        int socketfd = socket(AF_INET, SOCK_STREAM, 0);
        if (socketfd < 0)
        {
            perror("socket error");
            exit(1);
        }
    
        //2 connect
        struct sockaddr_in serveraddr;
        memset(&serveraddr, 0, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(SERVER_PORT);
    
        if(connect(socketfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0 )
        {
            perror("connect error");
            exit(1);
        }
    
        //3 read write
        char buf[1024];
      //read是阻塞函数 如果服务器没有下发消息,会一直阻塞在这里,知道收到消息。
    if (read(socketfd, buf, sizeof(buf)) > 0) { printf("%s",buf); } //4 close close(socketfd); return 0; }

    本例只是简单的处理,服务器返回客户端一个时间,然后关闭了socket。

    如果要进行双向通信,服务器势必要调用read函数,而read默认阻塞,那么如果客户端不向服务器发送数据,则主线程一直阻塞,其它客户端无法连接成功。这就需要处理高并发问题。

    服务器高并发处理的三种方式

    1. 多进程 https://www.cnblogs.com/lan0725/p/11634709.html
    2. 多线程 https://www.cnblogs.com/lan0725/p/11639142.html
    3.  I/O多路复用
  • 相关阅读:
    文本中溢出的文字在结尾显示为三个点
    git bash 如何建分支
    git本地仓库和远程仓库连接
    button不能直接添加href属性实现页面跳转
    【JAVA】【集合9】ArrayList和Vector区别
    【JAVA】【集合8】Java中的Vector
    【JAVA】【集合7】Java中的ArrayList
    【JAVA】【集合6】Java中的Collections工具类
    【JAVA】【集合5】Java中的List接口
    【JAVA】【集合4】Java中的Collection接口
  • 原文地址:https://www.cnblogs.com/lan0725/p/11634267.html
Copyright © 2011-2022 走看看