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;
}

运行结果:

相关推荐
黄筱筱筱筱筱筱筱1 小时前
LINUX-防火墙
linux·服务器·网络
сокол2 小时前
【网安-Web渗透测试-靶场系列】AWD-Platform(ctf-hub)
linux·服务器·ubuntu·网络安全·docker
utf8mb4安全女神2 小时前
Linux系统服务相关命令【定时任务设置】【任务进程管理】【防火墙区域应用】
linux·运维·服务器
L、2184 小时前
昇腾NPU性能调优Checklist——从“能跑“到“跑得快“的20步
服务器·人工智能·深度学习
liulilittle5 小时前
TCP UCP 卡尔曼滤波器
网络·网络协议·tcp/ip·通信
不吃土豆的马铃薯5 小时前
Spdlog 进阶:日志基本控制、日志格式控制、异步记录器
linux·服务器·开发语言·前端·c++
疯狂成瘾者5 小时前
常见的 Linux 版本
linux·运维·服务器
szxinmai主板定制专家6 小时前
基于ZYNQ MPSOC图像采集与压缩系统总体设计方案
linux·arm开发·人工智能·嵌入式硬件·fpga开发
GOTXX6 小时前
SenseNova U1 实战体验:API 调用 + OpenClaw 接入全流程
服务器·网络·人工智能·语言模型
liulilittle6 小时前
TCP UCP:基于卡尔曼滤波的BBR增强型拥塞控制算法
linux·网络·c++·tcp/ip·算法·c·通讯