美文网首页
基于Linux下C语言的Socket网络编程

基于Linux下C语言的Socket网络编程

作者: 步懒寻床 | 来源:发表于2019-01-16 11:06 被阅读0次

    基于Linux下C语言的Socket网络编程


    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

    Socket被广泛用作网络通信,它几乎支持所有的编程语言,各种语言对于Socket操作流程也比较类似。
    服务端程序的创建流程为创建socket——绑定端口号——监听——接受连接——读和写;
    客户端程序的创建流程为创建socket——通过IP和端口连接服务端——读和写。
    [TOC]

    服务端

    1. 创建Socket

    包含头文件:
    #include <sys/socket.h>
    #include <sys/types.h>
    函数原型:int socket(int domain, int type, int protocol);
    socket函数里有三个参数。
    domain选择通信协议族,常用的有以下几种。

    Name Purpose
    AF_UNIX, AF_LOCAL Local communication
    AF_INET(常用) IPv4 Internet protocols
    AF_INET6 IPv6 Internet protocols

    type指定Socket类型,常用以下几种。

    Name Purpose
    SOCK_STREAM 流式套接字(TCP协议)
    SOCK_DGRAM 数据报式套接字(UDP协议)

    protocol指定协议,常用以下几种

    NAME Purpose
    IPPROTO_TCP TCP传输协议
    IPPROTO_UDP UDP传输协议
    IPPROTO_STCP STCP传输协议
    IPPROTO_TIPC TIPC传输协议

    type和protocol不可以随意组合,当第三个参数type0自动选择第二个参数对应的默认协议

    Socket如果创建成功,则返回一个描述该网络通信端点的文件描述符,操作系统会自动分配当前最小可用的文件描述符。
    示例代码
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    2. 绑定端口号和IP地址

    包含头文件:
    #include <sys/socket.h>
    #include <sys/types.h>
    函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    bind()函数把地址族中的特定地址赋给socket。
    sockfdsocket描述字,通过socket创建,标识唯一一个服务端描述字。
    sockaddr结构体,通过初始化sockaddr_in结构体然后进行强制类型转化。示例代码如下:

    struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
    memset(server_socket, 0, sizeof (struct sockaddr_in)); // 清空sockaddr_in 结构体
    server_socket->sin_addr.s_addr = htonl(INADDR_ANY); // 任意IP地址
    server_socket->sin_family = AF_INET; // 使用IPv4协议族
    server_socket->sin_port = htons(PORT); // 端口号
    

    addrlensockaddr的长度。
    bind示例代码如下
    bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));

    3. 连接和监听

    包含头文件:
    #include <sys/socket.h>
    #include <sys/types.h>
    函数原型int listen(int sockfd, int backlog);
    sockfd为服务端建立socket的文件描述符
    backlog为对应socket可以排队的最大连接数
    服务端调用listen()函数监听socket,当客户端通过connect()函数连接服务端,发送连接请求时,listen()就会监听到这个请求。

    4. 接受客户端连接

    包含头文件:
    #include <sys/socket.h>
    #include <sys/types.h>
    函数原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    sockfd为服务端打开的socket描述字
    addr用于保存连接的客户端的IP地址和端口号,其内容与sockaddr结构体类似。
    addrlen是接受地址的长度。
    accept()函数如果执行成功,则返回一个由内核生成的全新的套接字,用于和新客户端之间通信。

    5. 读和写

    包含头文件:
    #include <unistd.h>
    函数原型:ssize_t read(int fd, void *buf, size_t count);
    函数原型:ssize_t write(int fd, const void *buf, size_t count);
    当socket打开网络描述字后,程序可以像读写文件一样向网络描述字读或者写,对应接受和发送数据。

    客户端

    1. 创建socket

    过程同服务端,socket返回的套接字描述符将直接用于和对端通信。

    2. 连接服务器

    函数原型int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    sockfd为客户端建立socket的文件描述符
    addr为sockaddr结构体保存的服务端的IP地址和端口号,以及协议类型,例如:

    struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in)); 
    memset(server_addr, 0, sizeof (struct sockaddr_in)); 
    server_addr->sin_family = AF_INET; // 使用IPv4协议族
    server_addr->sin_port = htons(port); // port为服务器绑定的端口号
    inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &server_addr->sin_addr); // 服务端的IP地址
    

    客户端发起tcp连接请求,服务端监听到请求并接受请求后,TCP连接建立即可以开始传输文件。(如果使用UDP协议有些许区别,暂时不做讨论。)

    3.发送数据

    连接建立后,客户端通过write()write()函数向打开的sockfd发送或接受数据

    代码示例

    Server

    #include <stdio.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/select.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define PORT 8000
    
    int main()
    {
        // 创建socket 
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        // 申请服务端和客户端地址结构体空间,客户端地址用于保存新连接的地址端口信息
        struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
        struct sockaddr_in *client_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
        socklen_t client_address_len;
        memset(server_socket, 0, sizeof (struct sockaddr_in));
        memset(client_socket, 0, sizeof (struct sockaddr_in));
        server_socket->sin_addr.s_addr = htonl(INADDR_ANY);
        server_socket->sin_family = AF_INET;
        server_socket->sin_port = htons(PORT);
        // 绑定
        bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));
        // 监听
        listen(sockfd, 20);
        // 接受
        int connect_fd = accept(sockfd, (struct sockaddr *)client_socket, &client_address_len);
        char buf[] = "Hello Wrold!";
        // 发送
        while(write(connect_fd, buf, strlen(buf)))
        {
            printf("send msg: %s\n", buf);
            sleep(1);
        }
        return 0;
    }
    
    

    Client

    #include <stdio.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/select.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        // 创建socket
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        // 准备地址结构体
        struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in));
        memset(server_addr, 0, sizeof (struct sockaddr_in));
        server_addr->sin_family = AF_INET;
        server_addr->sin_port = htons(8000);
        inet_pton(AF_INET, "127.0.0.1", &server_addr->sin_addr);
        // 连接
        connect(sockfd, (struct sockaddr *)server_addr, sizeof (struct sockaddr)); // sockaddr_in强制转换成sockaddr
        char buf[1024] = "";
        // 读取
        while(read(sockfd, buf, 1024))
        {
            printf("recv msg: %s\n", buf);
            memset(buf, 0, 1024);
        }
        return 0;
    }
    
    
    

    相关文章

      网友评论

          本文标题:基于Linux下C语言的Socket网络编程

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