基于Linux系统服务器与客户端网络通信

原理:TCP网络通信

服务端的流程:

  • 1、创建Socket套接字
  • 2、给这个socket绑定一个端口
  • 3、给这个socket开启监听属性 (这个只能用来接收和连接)
  • 4、等待客户端连接
  • 5、开始通讯
  • 6、关闭连接

客户端的流程:

  • 1、创建Socket套接字
  • 2、连接服务器
  • 3、开始通讯
  • 4、关闭连接

服务端代码:

1、创建套接字

//创建Socket套接字
int listen_socket =  socket(AF_INET,SOCK_STREAM,0);
if(-1 == listen_socket){
    printf("create listen socket failed !!! errcode:");
    return -1;
}

AF_INET 是指定套接字的协议簇,常见协议簇包括:

  • AF_INET:用于IPv4网络协议。这是最常用的协议族,适用于大多数基于TCP/IP的网络通信。
  • AF_INET6:用于IPv6网络协议。
  • AF_UNIX或AF_LOCAL:用于本地进程间通信(IPC),通常用于同一台机器上的进程间通信。

SOCK_STREAM指定套接字的类型。常见包括:

  • SOCK_STREAM:流式套接字,提供连接的、可靠的、双向的通信。最常用,适用于TCP。
  • SOCK_DGRAM:数据报套接字,提供无连接的、不可靠的通信。适用于UDP协议。
  • SOCK_RAW:原始套接字,允许直接访问低层协议,通常用于特殊用途。

0为指定具体协议,通常设为0,表示默认标识。对于SOCK_STREAM ,默认协议是TCP;对于 SOCK_STREAM,默认协议是UDP。

返回值,失败返回-1,成功返回非负整数。

2、给这个socket绑定一个端口

struct sockaddr_in local = {0};
local.sin_family = AF_INET;
local.sin_port = htons(8080);  
local.sin_addr.s_addr = inet_addr("0.0.0.0");
if(-1==bind(listen_socket, (struct sockaddr*)&local,sizeof(local))){
    printf("bind socket failed !!! errcode: ");
    return -1;
}

struct sockaddr_in表示是一个IPV4地址结构体,通常用于套接字编程。

sin_family:成员指定地址族

sin_port:成员指定端口号

sin_addr.s_addr:成员指定IP地址。

bind函数将套接字绑定到指定的地址和端口。如果绑定失败,返回值为-1

3、给这个socket开启监听属性

if(-1==listen(listen_socket, 10)){
    printf("start listen socket failed !!! ");
    return -1;
}

listen函数用于将套接字转换为监听套接字,使其能够接受传入的连接。10为未完成连接队列的最大长度。如果队列已满,新的连接请求将被拒绝。

    while (1)
    {
        /* code */
        int client_socket = accept(listen_socket, NULL, NULL);
        if(-1 == client_socket){
            continue;
        }
        // 5、开始通讯(B/S)
        /*int recv(
            SOCKET s;   //客户端的socket
            char* buf;  //接受的数据存在哪里
            int len;    //接受的长度
            int falgs;  //0
        )
        */
       pthread_t thread_id;
       int* sockfd = (int*)malloc(sizeof(int));
       *sockfd = client_socket;
       printf("%d\n",*sockfd);   
        pthread_create(&thread_id, 0, thread_function, sockfd);
       

    }

accept函数用于接受传入的连接,并为每个连接创建一个新的线程来处理通信。

线程池:

void* thread_function(void* arg) {
    int client_socket = *(int*)arg;
    printf("%d\n",client_socket);
    free(arg);
    while (1)
    {
        /* code */
        char buffer[1024]= {0};
        int ret = recv(client_socket,buffer, 1024,0);
        if(ret<=0)  {
            break;
        }
        printf("%d : %s\n",client_socket,buffer);
        send(client_socket,buffer,strlen(buffer),0);
    }
    close(client_socket);
    return 0;
}

客户端层次:

1、创建Socket套接字

    int client_socket = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == client_socket){
        printf("create socket failed !!");
        return -1;
    }

创建客户端套接字

2、连接服务器

    struct sockaddr_in target;
    target.sin_family = AF_INET;
    target.sin_port = htons(8080);  //大小端问题
    target.sin_addr.s_addr = inet_addr("127.0.0.1");
    if(-1 == connect(client_socket,(struct sockaddr*)&target,sizeof(target))){
        printf("connect server failed !!");
        close(client_socket);
        return -1;
    }

3、开始通讯

    while(1){
        char buffer[1024];
        printf("please input:");
        scanf("%s",buffer);
        send(client_socket,buffer,strlen(buffer),0);
        char rbuffer[1024]; 
        int ret = recv(client_socket,rbuffer,1024,0);
        if(ret<=0){
            break;
        }
        printf("%s\n",rbuffer);

    }

4、关闭连接

close(client_socket);

通过线程池可以实现多客户端同时与服务器进行信息发送。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值