Linux系统编程——TCP服务器

Linux系统编程------TCP服务器

服务器流程

  1. 创建流式套接字,通过socket实现
  2. 填充服务器的网络信息结构体,struct sockaddr_in
  3. 将套接字与服务器的网络信息结构体绑定,通过bind实现
  4. 将套接字设置成被动监听状态,通过listen实现
  5. 阻塞等待客户端连接,通过accept实现
  6. 收发数据,通过recv/send实现
  7. 关闭套接字,通过close实现

socket函数

c 复制代码
int socket(int domain, int type, int protocol);

所需头文件:sys/socket.h

功能:创建socket

domain:协议族

type:socket类型

protocol:附件协议,无协议写0

返回值:成功返回套接字,失败返回-1并设置errno

domain取值

说明
AF_INET IPV4
AF_INET6 IPV6
AF_PACKET 原始套接字使用
AF_UNIX 本地通信
AF_LOCAL 本地通信

socket取值

说明
SOCK_STREAM TCP使用
SOCK_DGRAM UDP使用
SOCK_RAW 原始套接字使用

bind函数

c 复制代码
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);

所需头文件:sys/socket.h

功能:将套接字与服务器的网络信息结构体绑定

sockfd:文件描述符,由socket函数返回

addr:地址结构体指针,指向要绑定给sockfd的协议地址,结构体根据创建sock时的协议族不同而不同,这里以IPV4为例。

addrlen:地址结构体长度

返回值:成功返回0,失败返回-1并设置errno

sockaddr结构体

c 复制代码
struct sockaddr_in {
	sa_family_t sin_family; /*地址族*/
	in_port_t sin_port; //16位端口号
	struct in_addr sin_addr //32位IP地址
};

struct in_addr{
	uint32_t s_addr; //32位IPV4地址
};

listen函数

c 复制代码
int listen(int sockfd, int backlog);

所需头文件:sys/socket.h

功能:将套接字设置成被动监听状态

sockfd:要监听的套接字

backlog:连接队列的长度

返回值:成功返回0,失败返回-1并设置errno

accept函数

c 复制代码
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);

功能:阻塞等待客户端连接

sockfd:处于监听状态的socket

addr:用于保存客户端地址的结构体指针,如果不关系客户端信息,可以传NULL

addrlen:输入时为addr的缓冲区大小,输出时为实际地址长度,如果不关系客户端信息,可以传NULL。

返回值:成功返回新的socket文件描述符(由内核生成,代表着与返回客户端TCP连接,专用于与客户端通信),失败返回-1并设置errno

recv函数

c 复制代码
ssize_t recv(int sockfd, void* buf, size_t len, int flags);

所需头文件:sys/socket.h

功能:接收数据

sockfd:客户端的socket套接字

buf:存储接受的数据

len:数据大小

flags:控制选项(如MSG_DONTWAIT非阻塞,MSG_PEEK窥视数据, 0阻塞)

返回值:成功返回实际接受数据字节数,失败返回-1并设置errno

send函数

c 复制代码
ssize_t send(int sockfd, const void* buf, size_t len, int flags);

所需头文件:sys/socket.h

功能:发送数据

sockfd:客户端的sock套接字

buf:要发送数据的首地址

len:数据大小

flags:控制选项(如MSG_DONTWAIT非阻塞,MSG_PEEK窥视数据, 0阻塞)

返回值:成功返回实际发送数据字节数,失败返回-1并重置错误码

close函数

c 复制代码
int close(int fd);

所需头文件:unistd.h

fd:要关闭的套接字

返回值:成功返回0,失败返回-1

实例:实现一个TCP服务器

代码:

c 复制代码
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>

int main(int argc, char** argv) {
    //创建流式套接字
    struct sockaddr_in server_info;
        struct sockaddr_in client_info;
    socklen_t client_info_len = sizeof(client_info);
        int ret;
    int listen_fs = socket(AF_INET, SOCK_STREAM, 0);
        if (listen_fs < 0) {
            perror("socket创建失败");
                return -1;
        }

        //配置服务器地址结构体
        //清空结构体
    memset(&server_info, 0, sizeof(server_info));
    memset(&client_info, 0, sizeof(client_info));
        //初始化IPV4协议族
        server_info.sin_family = AF_INET;
    //初始化端口号
    server_info.sin_port = htons(8888);
        //初始化IP
    server_info.sin_addr.s_addr = inet_addr("192.168.203.141");
        //绑定套接字与地址
    ret = bind(listen_fs,(struct sockaddr*)&server_info, sizeof(server_info));
        if (ret < 0) {
            perror("绑定失败");
                return -1;
        }
    //监听
        ret = listen(listen_fs, 128);
    if (ret < 0) {
            perror("监听失败");
                return -1;
        }

        //循环等待客户端连接
    while(true) {
            int connect_fd = accept(listen_fs,(struct sockaddr*)&client_info, client_info_len );
        if(connect_fd == -1) {
                    perror("等待连接失败");
                        return -1;
                }
                printf("客户端[%s:%d] 连接到服务器", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
                //处理客户端通信(内部循环);
            while(true) {
                    char buf[128] = {0};
                        //int nbtyes = read(connect_fd, buf, sizeof(buf));
                        int nbytes = recv(connect_fd, buf, sizeof(buf), 0);
                        if (nbytes == -1) {
                            perror("读取失败");
                                return -1;
                        }

                        if (nbytes == 0) {
                            printf("客户端断开连接\n");
                                break;
                        }
                        printf("客户端[%s:%d]发来的数据:%s\n",inet_ntoa(client_info.sin_addr),ntohs(client_info.sin_port), buf);

                        //回显数据
                   int nbytes_send = send(connect_fd, buf, sizeof(buf), 0);
                   if (nbytes_send == -1) {
                      perror("发送失败");
                          return  -1;
                   }
                }
        }
        return 0;
}

运行结果:

相关推荐
小Tomkk2 分钟前
数据库 变更和版本控制管理工具 --Bytebase 安装部署(linux 安装篇)
linux·运维·数据库·ci/cd·bytebase
赌博羊3 分钟前
ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32‘ not found
linux·运维·gnu
木卫二号Coding5 分钟前
第七十九篇-E5-2680V4+V100-32G+llama-cpp编译运行+Qwen3-Next-80B
linux·llama
getapi13 分钟前
Ubuntu 22.04 服务器的系统架构是否为 amd64 x86_64
linux·服务器·ubuntu
消失的旧时光-194330 分钟前
Linux 入门核心命令清单(工程版)
linux·运维·服务器
艾莉丝努力练剑38 分钟前
【Linux:文件】Ext系列文件系统(初阶)
大数据·linux·运维·服务器·c++·人工智能·算法
Trouvaille ~1 小时前
【Linux】TCP Socket编程实战(一):API详解与单连接Echo Server
linux·运维·服务器·网络·c++·tcp/ip·socket
科技块儿1 小时前
利用IP查询在智慧城市交通信号系统中的应用探索
android·tcp/ip·智慧城市
极新2 小时前
智启新篇,智创未来,“2026智造新IP:AI驱动品牌增长新周期”峰会暨北京电子商务协会第五届第三次会员代表大会成功举办
人工智能·网络协议·tcp/ip
M158227690552 小时前
TCP转LORA产品说明及应用案例
网络·网络协议·tcp/ip