Linux 下使用select 实现TCP server和TCP client

基于TCP(面向链接)的socket编程

Server端的流程如下:

  • 1 创建Socket套接字

  • 2 将套接字绑定到一个本地地址(IP)和端口(port)上

  • 3 将套接字设置为监听模式,准备接收客户端请求(listen)

  • 4 等待客户端请求,当请求到来后,接受链接请求,返回一个新的对应于此次链接的套接字(accept)

  • 5 用返回的套接字和客户端进行通信(send/recv read/write)

  • 6 返回,等待另一个客户请求

  • 7 关闭套接字

/*
*tcp_server.c
*/
#include "tcp-server.h"

#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>


static const size_t MAX_FRAME_SIZE = 4100;
static const int PORT = 1234;

static device_t tcp_device;
static int listen_fd = -1;
static int tcp_server_init(device_t *dev) {
   
    struct sockaddr_in addr;
    //创建socket,获取一个socket描述符
    if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
   
        fprintf(stderr, "%s(): cannot create socket", __FUNCTION__);
        return -1;
    }
    //设置server的地址同通信协议
    memset(&addr, 0, sizeof(struct sockaddr_in));
    //协议族: AF_INET AF_INET6 AF_LOCAL
    addr.sin_family = AF_INET;
    //取本地任意一个地址进行通信
    // uint32_t htonl(uint32_t hostlong) 将主机无符号长整型转化为网络字节
    //INADDR_ANY=0.0.0.0
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // uint16_t htons(uint16_t hostshort) 将hostshort 转化为网络字节序
    //网络字节采用大端模式(big-ending),高位存放在低地址
    addr.sin_port = htons(PORT);
    if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
   
        fprintf(stderr, "%s(): bind() failed", __FUNCTION__);
        goto failed;
    }
    if (listen(listen_fd, LISTEN_BACKLOG) != 0) {
   
        fprintf(stderr, "%s(): listen() failed", __FUNCTION__);
        goto failed;
    }
    fprintf(stderr, "%s(): tcp_server running on %s port=%d\n", __FUNCTION__, inet_ntoa(addr.sin_addr), PORT);
    dev->recv_buf = (
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Windows下,可以使用select函数来检测客户端连接是否断开。select函数可以监视多个套接字的状态,当有套接字状态发生变化时,select函数就会返回。如果客户端连接断开,相应的套接字状态也会发生变化,通过检测套接字状态可以判断客户端连接是否断开。 以下是使用select函数检测客户端连接是否断开的示例代码: ```c #include <winsock2.h> #include <stdio.h> int main() { // 初始化Winsock WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed.\n"); return 1; } // 创建监听套接字 SOCKET listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSock == INVALID_SOCKET) { printf("socket failed.\n"); WSACleanup(); return 1; } // 绑定监听套接字 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = INADDR_ANY; if (bind(listenSock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { printf("bind failed.\n"); closesocket(listenSock); WSACleanup(); return 1; } // 开始监听 if (listen(listenSock, SOMAXCONN) == SOCKET_ERROR) { printf("listen failed.\n"); closesocket(listenSock); WSACleanup(); return 1; } // 创建fd_set并将监听套接字添加进去 fd_set readSet; FD_ZERO(&readSet); FD_SET(listenSock, &readSet); // 循环等待客户端连接 while (true) { // 调用select函数等待客户端连接或数据到达 fd_set tempSet = readSet; int ret = select(0, &tempSet, NULL, NULL, NULL); if (ret == SOCKET_ERROR) { printf("select failed.\n"); break; } // 检测监听套接字是否有连接请求 if (FD_ISSET(listenSock, &tempSet)) { SOCKET clientSock = accept(listenSock, NULL, NULL); if (clientSock == INVALID_SOCKET) { printf("accept failed.\n"); break; } printf("client connected.\n"); // 将新连接的客户端套接字添加进fd_set FD_SET(clientSock, &readSet); } // 检测客户端套接字是否有数据到达或连接断开 for (int i = 0; i < readSet.fd_count; i++) { SOCKET sock = readSet.fd_array[i]; if (sock != listenSock && FD_ISSET(sock, &tempSet)) { char buf[1024]; int ret = recv(sock, buf, sizeof(buf), 0); if (ret == SOCKET_ERROR || ret == 0) { // 客户端连接断开,将套接字从fd_set中删除 printf("client disconnected.\n"); closesocket(sock); FD_CLR(sock, &readSet); } else { // 处理接收到的数据 // ... } } } } // 关闭监听套接字 closesocket(listenSock); // 清理Winsock WSACleanup(); return 0; } ``` 注意:以上代码仅为示例代码,实际使用时还需要进行错误处理和异常情况处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值