一个简单的socket网络编程


1 socket编程流程

1.1 创建socket

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

domain 用于指定底层协议族,对 TCP/IP 协议族来说,应设置为 PF_INET(IPv4)或 PF_INET6(IPv6);type 用于指定服务类型,对 TCP/IP 族来说,SOCK_STREAM 表示使用 TCP 协议,SOCK_STREAM 表示使用 UDP 协议;protocol 是再选择一个具体的协议,一般设为 0 使用默认协议即可。

1.2 命名socket

在服务端,需要调用 bind 将 socket 与 socket 地址进行绑定,在客户端则不需要调用 bind 进行绑定,操作系统会自动分配地址,当然也可以自行调用 bind 进行地址绑定,但是没有那个必要。

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

所有专用 socket 地址(比如 TCP/IP 协议族的 sockaddr_in 和 sockaddr_in6 等)在使用时都需要转换为通用 socket 地址 sockaddr, 所以在传入第二个参数时往往需要进行强制转换。

1.3 监听socket

调用 listen 指定被监听的 socket 和监听队列的最大长度。

int listen(int sockfd, int backlog);

1.4 接受连接

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

1.5 发起连接

客户端通过 connect 与服务器建立连接。

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

2 代码示例

2.1 服务端

#include
#include
#include
#include
#include
#include
#include 
#include

const int BUFSIZE = 1024;

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

    if(argc <= 3){
        printf("usage: %s ip_adderss port number backlog\n", basename(argv[0]));
        return 1;
    }

    const char *ip = argv[1];
    int port = atoi(argv[2]);  //字符串转换整数
    int backlog = atoi(argv[3]);

    /*创建socket*/
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockfd >= 0);

    /*创建socket地址*/
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);  //主机字节序转换网络字节序
    inet_pton(AF_INET, ip, &address.sin_addr);

    int ret = bind(sockfd, (struct sockaddr*) &address, sizeof(address));  //绑定socket地址
    assert(ret != -1);

    /*监听socket*/
    ret = listen(sockfd, backlog);
    assert(ret != -1);

    printf("Waiting for connection...\n");

    struct sockaddr_in client;
    
    while(true){
        
        socklen_t client_length = sizeof(client);
        /*accept连接*/
        int connfd = accept(sockfd, (struct sockaddr *)&client, &client_length); 
        if(connfd < 0){
            printf("errno is: %d\n", errno);
            break;
        }

        printf("From client: IP is %s and Port is %d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));  //输出客户端IP和端口

        /*数据读写*/
        char recv_buffer[BUFSIZE];
        int n = recv(connfd, recv_buffer, BUFSIZE, 0);
        recv_buffer[n] = '\0';
        printf("Got %d bytes of data: %s\n", n, recv_buffer);

        close(connfd);
    }

    close(sockfd);

    return 0;
}

2.2 客户端

#include
#include
#include
#include
#include
#include
#include 
#include

const int BUFSIZE = 1024;

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

    if(argc <= 2){
        printf("usage: %s ip_adderss port number\n", basename(argv[0]));
        return 1;
    }

    const char *ip = argv[1];
    int port = atoi(argv[2]);  //字符串转换整数

    /*创建socket*/
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockfd >= 0);

    /*创建socket地址*/
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);  //主机字节序转换网络字节序
    inet_pton(AF_INET, ip, &address.sin_addr);

    /*发起连接*/
    if(connect(sockfd, (struct sockaddr *)&address, sizeof(address)) < 0){
        printf("Connection failed\n");
        exit(1);
    }

    /*数据读写*/
    printf("Please enter information to the server:\n");
    char send_buffer[BUFSIZE];
    fgets(send_buffer, BUFSIZE, stdin);
    if(send(sockfd, send_buffer, strlen(send_buffer), 0) < 0){
        printf("errno is: %d\n", errno);
        exit(1);
    }

    close(sockfd);
    return 0;
}

相关