zoukankan      html  css  js  c++  java
  • Socket编程实践(3) --Socket API

    socket函数

    #include <sys/types.h>
    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);

    创建一个套接字用于通信

    参数:

       domain:指定通信协议族(protocol family),常用取值AF_INET(IPv4)

       type:指定socket类型, 流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW

       protocol:协议类型,常用取值0, 使用默认协议

    返回值:

       成功: 返回非负整数,套接字;

       失败: 返回-1


    bind函数

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

    绑定一个本地地址到套接字

    参数:

       sockfd:socket函数返回的套接字

       addr:要绑定的地址

    //sockaddr_in结构, bind时需要强制转换成为struct sockaddr*类型
    struct sockaddr_in
    {
        sa_family_t    sin_family; /* address family: AF_INET */
        in_port_t      sin_port;   /* port in network byte order */
        struct in_addr sin_addr;   /* internet address */
    };
    /* Internet address. */
    struct in_addr
    {
        uint32_t       s_addr;     /* address in network byte order */
    };
    /**示例:INADDR_ANY的使用, 绑定本机任意地址**/
    int main()
    {
        int listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd == -1)
            err_exit("socket error");
    
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8001);
        //绑定本机的任意一个IP地址, 作用同下面两行语句
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        //inet_aton("127.0.0.1", &addr.sin_addr);
        //addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)
            err_exit("bind error");
        else
            cout << "bind success" << endl;
    }

    listen函数

    int listen(int sockfd, int backlog);

       listen函数应该用在调用socketbind函数之后, 并且用在调用accept之前用于将一个套接字从一个主动套接字转变成为被动套接字。

    backlog说明:

    对于给定的监听套接口,内核要维护两个队列:

       1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程(SYN_RCVD状态)

       2、已完成连接的队列(ESTABLISHED状态)

    但是两个队列长度之和不能超过backlog


    backlog推荐使用SOMAXCONN(3.13.0-44-generic中该值为128), 使用等待队列的最大值;

     

    Man-Page中的listen说明:

       listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that 

    will be used to accept incoming connection requests using accept(2).

       The sockfd argument is a file descriptor that refers to a socket of type  SOCK_STREAM  or 

    SOCK_SEQPACKET.

       The backlog argument defines the maximum length to which the queue of pending connections for 

    sockfd may grow.  If a connection request arrives when the queue is full, the  client may  receive

    an  error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, 

    the request may be ignored so that a later reattempt at  connection succeeds.

      If the backlog argument is greater than the value in  /proc/sys/net/core/somaxconn(Ubuntu 14.04 该值为128),  then it  is  silently truncated to that value; the default value in this file is 128.  In kernels

    before 2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.

     

    accept函数

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

    已完成连接队列返回第一个连接(the first connection request on the queue of  pending  connections  for the listening 

    socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. 

    The newly created socket  is  not  in  the listening state),如果已完成连接队列为空,则阻塞。The original 

    socket sockfd is unaffected by this call.

     

    参数:

       sockfd:服务器套接字

       addr:将返回对等方的套接字地址, 不关心的话, 可以设置为NULL

       addrlen:返回对等方的套接字地址长度, 不关心的话可以设置成为NULL, 否则一定要初始化

    返回值:

       On  success, these system calls return a non-negative integer that is a descriptor for the accepted 

    socket.  On error, -1 is returned, and errno is set appropriately.

     

    connect函数

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

    建立一个连接至addr所指定的套接字

    参数:

       sockfd:未连接套接字

       addr:要连接的套接字地址

       addrlen:第二个参数addr长度

     

    示例:echo server/client实现

    //server端代码
    int main()
    {
        int listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd == -1)
            err_exit("socket error");
    
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8001);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)
            err_exit("bind error");
        if (listen(listenfd, SOMAXCONN) == -1)
            err_exit("listen error");
    
        char buf[512];
        int readBytes;
        struct sockaddr_in clientAddr;
        //谨记: 此处一定要初始化
    socklen_t addrLen = sizeof(clientAddr);
        while (true)
        {
            int clientfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);
            if (clientfd == -1)
                err_exit("accept error");
            //打印客户IP地址与端口号
            cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)
                 << ", " << ntohs(clientAddr.sin_port) << endl;
    
            memset(buf, 0, sizeof(buf));
            while ((readBytes = read(clientfd, buf, sizeof(buf))) > 0)
            {
                cout << buf;
                if (write(clientfd, buf, readBytes) == -1)
                    err_exit("write socket error");
                memset(buf, 0, sizeof(buf));
            }
            if (readBytes == 0)
            {
                cerr << "client connect closed..." << endl;
                close(clientfd);
            }
            else if (readBytes == -1)
                err_exit("read socket error");
        }
        close(listenfd);
    }
    //client端代码
    int main()
    {
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1)
            err_exit("socket error");
    
        //填写服务器端口号与IP地址
        struct sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(8001);
        serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        if (connect(sockfd, (const struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
            err_exit("connect error");
    
        char buf[512];
        while (fgets(buf, sizeof(buf), stdin) != NULL)
        {
            if (write(sockfd, buf, strlen(buf)) == -1)
                err_exit("write socket error");
            memset(buf, 0, sizeof(buf));
            int readBytes = read(sockfd, buf, sizeof(buf));
            if (readBytes == 0)
            {
                cerr << "server connect closed... 
    exiting..." << endl;
                break;
            }
            else if (readBytes == -1)
                err_exit("read socket error");
            cout << buf;
            memset(buf, 0, sizeof(buf));
        }
        close(sockfd);
    }

    附-Makefile

    .PHONY: clean all 
    CC = g++ 
    CPPFLAGS = -Wall -g -pthread -std=c++11
    BIN = server client
    SOURCES = $(BIN.=.cpp)
    
    all: $(BIN)
    $(BIN): $(SOURCES) 
    
    clean:
        -rm -rf $(BIN) bin/ obj/ core


  • 相关阅读:
    c++程序—冒泡排序法(函数、指针)
    c++程序—统计成绩
    c++程序—冒泡排序法
    c++程序—逆置
    c++程序—五只小猪称体重
    c++程序—goto
    c++程序—乘法表
    c++程序—循环嵌套
    RGB保存 .bmp文件踩坑记
    vdi文件扩容
  • 原文地址:https://www.cnblogs.com/itrena/p/5926939.html
Copyright © 2011-2022 走看看