Linux下C/C++ Socket服务器的简单实现和详细解析

在linux系统下用C/C++ Socket实现最简单的服务器,并解释使用到的函数。

1 创建Socket

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

参数说明:

  • domain:表示要使用的网络协议族,常见的取值有:
    • AF_INET:IPv4协议族。
    • AF_INET6:IPv6协议族。
    • AF_UNIX:UNIX域协议族(用于本地进程间通信)。
  • type:表示套接字类型,常见的取值有:
    • SOCK_STREAM:面向连接的流套接字,在TCP协议中使用。
    • SOCK_DGRAM:无连接的数据报套接字,在UDP协议中使用。
  • protocol:指定协议类型,通常设置为0,表示根据domaintype自动选择合适的协议。

返回值:

  • 成功:返回新创建的套接字描述符。
  • 失败:返回-1,并设置全局变量errno表示错误代码。

2 命名Socket

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);

参数说明: 

  • sockfd:表示要进行绑定的套接字的文件描述符。
  • addr:指向 struct sockaddr 类型的指针,它表示要绑定的地址。通常会使用 struct sockaddr_in 结构体来表示 IPv4 地址(也可以使用 struct sockaddr_in6 来表示 IPv6 地址)。
  • addrlen:表示 addr 的长度。

其中addr通常使用sockaddr_in结构如下:

#include <netinet/in.h>
struct sockaddr_in {
    sa_family_t sin_family;         // 地址族AF_INET
    in_port_t sin_port;             // 16 位端口号
    struct in_addr sin_addr;        // 32 位 IP 地址
};

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置全局变量errno表示错误代码 。

3 监听Socket

#include <sys/socket.h>
int listen(int sockfd, int backlog);

 参数说明: 

  • sockfd:表示要监听的套接字的文件描述符。
  • backlog:表示监听队列的最大长度。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并设置全局变量errno表示错误代码 。

4 接受连接

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);

参数说明:  

  • sockfd:表示监听套接字的文件描述符。
  • addr:指向用于存储远程客户端地址的结构体指针,可以为 NULL
  • addrlen:表示 addr 结构体的长度。

返回值:

  • 成功:返回新创建的套接字的文件描述符。
  • 失败:返回-1,并设置全局变量errno表示错误代码 。

此处注意accept函数返回的是一个新的套接字,后续和该客户端通信都使用该套接字。

5 读取数据

#include <sys/socket.h>
int recv(int sockfd, void* buf, size_t len, int flags);

参数说明:

  • sockfd:要接收数据的套接字描述符。
  • buf:用于存储接收数据的缓冲区的指针。
  • len:要接收的数据的最大长度。
  • flags:可选的标志参数,用于控制接收操作的行为,如:
    • 0:默认标志,无特殊行为。
    • MSG_PEEK:从接收缓冲区中查看数据,但不将其从缓冲区中删除(下一次调用recv仍然可以接收到同样的数据)。
    • MSG_WAITALL:读操作仅在读取到指定数量的字节后返回。
    • MSG_DONTWAIT:非阻塞模式。

返回值:

  • 成功:返回实际读取的字节数。
  • 对方关闭连接:返回0。
  • 失败:返回-1,并设置全局变量errno表示错误代码 。

完整代码

给出完整的简易服务器代码。

//server.cpp
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main() {
    // 创建Socket
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);

    // 准备服务器地址
    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port = htons(5712); // 端口号

    // 绑定地址和端口
    bind(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress));

    // 监听连接
    listen(serverSocket, 5);

    std::cout << "Server started." << std::endl;

    // 接受客户端连接
    struct sockaddr_in clientAddress;
    socklen_t clientAddressSize = sizeof(clientAddress);
    int clientSocket = accept(serverSocket, (struct sockaddr *) &clientAddress, &clientAddressSize);
    std::cout << "New client connection accepted." << std::endl;

    char buffer[1024] = {0};

    // 读取客户端数据
    ssize_t bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);

    // 打印客户端发送的数据
    std::cout << "Received from client: " << buffer << std::endl;

    // 关闭客户端连接
    close(clientSocket);

    // 关闭服务器Socket
    close(serverSocket);

    return 0;
}

测试

编译运行服务器程序。

g++ server.cpp -o server
./server

另开一个终端,用nc指令作为客户端简单测试一下服务器。

nc 127.0.0.1 5712
Hello!

服务端显示相应信息,测试成功!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值