(Linux)TCP实现服务器和客户端通信+详细注释

本文详细介绍了如何使用C语言实现一个基础的TCP服务器,包括创建套接字、绑定地址、监听连接、接收和转发客户端消息,以及创建一个简单的聊天室功能。
摘要由CSDN通过智能技术生成

代码实现

server(服务器端)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>

// ./server 192.168.154.128 1234  命令行中打开服务端
// 192.168.154.128是我服务器的ip地址 1234是端口号
int main(int argc,char *argv[]){
    //使用socket函数 创建流式套接字
    int sockFd = socket(AF_INET,SOCK_STREAM,0);
    if(sockFd < 0){
        perror("socket err");
        return -1;
    }
    int optval = 1;
    //修改不让服务端进入wait_time状态
    int ret = setsockopt(sockFd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int));
    struct sockaddr_in addr;
    //填充IPv4结构体
    //设置地址族为IPv4
    addr.sin_family = AF_INET; 
    //端口占了两个字节 将小端转为大端 也就是命令输入的第三个参数
    addr.sin_port = htons(atoi(argv[2]));
    //绑定IP地址  命令行输入的第二个参数
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    //绑定套接字,ip和端口 
    ret = bind(sockFd,(struct sockaddr *)&addr,sizeof(addr));
    if(ret < 0){
        perror("bind");
        return -1;
    }
    else{
        printf("bind ok\n");
    }
    //监听 设置监听队列大小为5
    //listen函数是用于在服务器端套接字上监听连接请求的操作
    ret = listen(sockFd,10);
    if(ret < 0){
        perror("listen err");
        return -1;
    }
    fd_set rdset; //单纯地去保存就绪的文件描述符
    fd_set monitorSet; //使用一个单独的监听集合
    FD_ZERO(&monitorSet);
    FD_SET(STDIN_FILENO,&monitorSet);
    FD_SET(sockFd,&monitorSet);
    char buf[4096] = {0};
    int netFd = -1;
    while(1){
        //将监听集合复制给rdset
        memcpy(&rdset,&monitorSet,sizeof(fd_set));
        //select一直置于阻塞状态,直到监控到文件描述符集合中某个文件描述符发生变化为止
        select(20,&rdset,NULL,NULL,NULL);
        if(FD_ISSET(STDIN_FILENO,&rdset)){
            if(netFd == -1){  //表示目前没有连接
                puts("no client is connected!\n");
                continue;
            }
            //否则表示有连接 首先清空缓冲区
            bzero(buf,sizeof(buf));
            //从标准输入中读取数据,并将其存储在buf数组中。read函数返回实际读取的字节数
            ret = read(STDIN_FILENO,buf,sizeof(buf));
            //ret == 0时 表示读到终止符  服务器主动断开连接
            if(ret == 0){
                //发送byebye给客户端
                send(netFd,"byebye",6,0);
                break;
            }
            //将数据发给客户端
            send(netFd,buf,strlen(buf),0);
        }
        if(FD_ISSET(sockFd,&rdset)){
            //接受客户端的连接请求 并赋值给文件描述符netFd
            netFd = accept(sockFd,NULL,NULL);
            //加入监听集合
            FD_SET(netFd,&monitorSet);
            puts("new connect is accept!\n");//表示有连接抵达
        }
        if(FD_ISSET(netFd,&rdset)){
            bzero(buf,sizeof(buf));
            //接受客户端发来的数据
            ret = recv(netFd,buf,sizeof(buf),0);
            //表示客户端主动断开连接 发送byebye给服务端
            if(ret == 0){
                puts("bye bye");
                //将netFd从监听集合移出
                FD_CLR(netFd,&monitorSet);
                //关闭文件描述符
                close(netFd);
                netFd = -1;
                continue;
            }
            //将服务端从客户端收到的数据打印出来
            puts(buf);
        }
    }
    close(netFd);
    //关闭套接字
    close(sockFd);
}

代码分析

1.使用socket函数创建一个IPv4的TCP套接字
2.利用bind函数将套接字绑定到指定IP和端口上
3.使用listen函数将套接字设置为监听状态,设置了监听队列的长度为10
4.使用accept函数等待客户端连接请求,并返回连接套接字的文件描述符
5.在一个while循环中循环接收客户端发送的消息,然后将接收到的消息输出到终端
6.关闭套接字

该程序实现了一个简单的TCP服务器的功能,可以接收客户端的连接,并且循环接收客户端发送的消息,将接收到的消息输出到终端

client(客户端)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>

int main(int argc,char *argv[]){
    // ./client 192.168.154.128 1234  打开客户端
    //使用socket创建流式套接字
    int sockFd = socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    //客户端端需要调用connect()连接服务器,connect和bind的参数形式一致,
    //区别在于bind的参数是自己的地址,而connect的参数是对方的地址.
    int ret = connect(sockFd,(struct sockaddr *)&addr,sizeof(addr));
    if(ret < 0){
        perror("connect error!\n");
    }
    else{
        printf("connect ok!\n");
    }
    fd_set rdset;
    char buf[4096] = {0};
    while(1){
        FD_ZERO(&rdset);
        FD_SET(STDIN_FILENO,&rdset);
        FD_SET(sockFd,&rdset);
        select(sockFd+1,&rdset,NULL,NULL,NULL);
        if(FD_ISSET(STDIN_FILENO,&rdset)){
            bzero(buf,sizeof(buf));
            ret = read(STDIN_FILENO,buf,sizeof(buf));
            if(ret == 0){
                //客户端主动断开连接
                send(sockFd,"byebye",6,0);
                break;
            }
            send(sockFd,buf,strlen(buf),0);
        }
        if(FD_ISSET(sockFd,&rdset)){
            bzero(buf,sizeof(buf));
            ret = recv(sockFd,buf,sizeof(buf),0);
            //读到终止符 表示服务器断开连接了
            if(ret == 0){
                puts("chat is end!");
                break;
            }
            puts(buf);
        }
    }
    //关闭套接字
    close(sockFd);
}

代码分析

这是一个TCP客户端代码,它的主要功能是连接到指定的服务器,并且有发送消息接收消息的功能

1.socket函数创建了一个流式套接字

2.connect函数表示连接到服务器,这个函数将套接字连接到 sockaddr_in 结构体中描述的IP地址和端口号,如果连接失败,将返回一个负数值

3.read函数从标准输入读取数据,并将其存储在 buf 中

4.send函数将读取的数据发送到服务器

5.close函数关闭套接字

在主循环中,该客户端将不断地从标准输入读取数据并将其发送到服务器,直到程序被强制终止

serverroom(聊天室)

客户端代码不变,仅对服务端稍加修改,就可以达到一个类似聊天室的功能

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>

int main(int argc,char *argv[]){
    // ./serverroom 192.168.154.128 1234
    int sockFd = socket(AF_INET,SOCK_STREAM,0);
    int optval = 1;
    //修改不让服务端进入wait_time状态
    int ret = setsockopt(sockFd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int));
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    ret = bind(sockFd,(struct sockaddr *)&addr,sizeof(addr));
    if(ret < 0){
        perror("bind");
        return -1;
    }
    else{
        printf("bind ok\n");
    }
    ret = listen(sockFd,10);
    fd_set rdset; //单纯地去保存就绪的文件描述符
    fd_set monitorSet; //使用一个单独的监听集合
    FD_ZERO(&monitorSet);
    FD_SET(sockFd,&monitorSet);
    char buf[4096] = {0};
    int netFdArr[10] = {0};
    int curConn = 0;
    //1.实现聊天室
    //服务器不再监听标准输入 
    //服务端的功能:1.处理新的客户端连接 
    //2.处理客户端发送的消息转发
    //维护netFd数组 然后进行转发
    while(1){
        memcpy(&rdset,&monitorSet,sizeof(fd_set));
        select(20,&rdset,NULL,NULL,NULL);
        //现在只能发送信息不能接收信息了
        if(FD_ISSET(sockFd,&rdset)){
            netFdArr[curConn] = accept(sockFd,NULL,NULL);
            if(netFdArr[curConn] < 0){
                perror("accept error!\n");
            }
            FD_SET(netFdArr[curConn],&monitorSet);
            printf("new connect is accept!, curConn = %d\n",curConn);
            ++curConn;
        }
        int i;
        for(i = 0; i < curConn; ++i){
            if(FD_ISSET(netFdArr[i],&rdset)){
                bzero(buf,sizeof(buf));
                recv(netFdArr[i],buf,sizeof(buf),0);
                int j;
                for(j = 0; j < curConn; ++j){
                    if(j == i){
                        continue;
                    }
                    send(netFdArr[j],buf,strlen(buf),0);
                }
            }
        }
    }
    close(sockFd);
}

结果展示

编译server.c

g++ server.c -o server

编译client.c

g++ client.c -o client

开启服务端

在命令行输入

./server 192.168.154.128 1234

开启客户端

./client 192.168.154.128 1234

聊天室功能展示

以上是TCP实现了简单的服务器客户端通信,谢谢大家观看!

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: C语言中实现基于TCP协议的服务器客户端通信,需要使用Socket编程。下面是一些基本步骤: 1. 建立服务器 首先需要建立服务器端的socket。通过调用socket()函数创建服务器socket,指定socket的协议族(通常是AF_INET,即IPv4),socket类型(通常是SOCK_STREAM,即TCP流式套接字),和端口号。之后调用bind()函数把服务器socket绑定到指定的地址和端口。接下来就可以调用listen()函数开始监听客户端连接请求。 2. 连接客户端 客户端需要调用socket()函数创建socket,同样指定协议族、socket类型和端口号(这里可以随机指定一个未占用的端口号)。之后调用connect()函数连接服务器的地址和端口号即可。 3. 通信 一旦客户端服务器端建立连接,就可以通过读写socket进行通信服务器端需要调用accept()函数接受客户端连接请求,返回一个新的socket描述符用于和客户端进行通信。之后可以使用send()函数向客户端发送数据,使用recv()函数从客户端接收数据。客户端同样可以使用send()和recv()函数进行通信。 4. 结束连接 通信结束后,服务器客户端需要分别调用close()函数关闭链接。 以上是基于TCP协议的服务器客户端通信的基本步骤,具体实现过程需要详细的代码实现。在实际开发中,还需要注意处理错误和异常情况,以保证程序的稳定性和安全性。 ### 回答2: 基于TCP协议的服务器客户端通信是一种常见的网络通讯方式。服务器网络上侦听特定端口,接收客户端的连接请求。当连接建立后,服务器客户端之间可以进行数据传输。 实现基于TCP协议的服务器客户端通信,需要遵循以下步骤: 1. 创建服务器端的套接字(socket)并绑定IP地址和端口号。 2. 监听客户端的连接请求,等待客户端连接。 3. 接受客户端的连接请求,创建一个与客户端通信的套接字。 4. 使用套接字进行数据传输,包括从客户端接收请求和向客户端发送响应。 5. 当通信完成后,关闭连接并释放资源。 对于客户端,需要以下步骤: 1. 创建客户端的套接字。 2. 连接服务器套接字。 3. 发送请求数据给服务器。 4. 接收服务器响应数据。 5. 关闭连接并释放资源。 在实现过程中,还需要注意以下方面: 1. 使用正确的IP地址和端口号进行通信。 2. 服务器端需要使用多线程或多进程进行并发处理,以支持多个客户端同时连接。 3. 通信过程中需要加入一定的数据校验和错误处理机制,以提高通讯的可靠性。 总之,基于TCP协议的服务器客户端通信是一种灵活、可靠的网络通讯方式,可以广泛应用于各种网络场景中,例如打印、文件传输、远程控制等。 ### 回答3: C 11是一种编程语言,可以用来实现基于TCP服务器客户端通信TCP是传输控制协议的缩写,它提供了一种可靠的数据传输方式,被广泛用于互联网上的通信。 要实现基于TCP服务器客户端通信,需要用C 11语言编写两个程序:一个服务器程序和一个客户端程序。服务器程序在运行时监听一个指定的端口,等待客户端程序的连接请求。当客户端请求连接时,服务器程序接受连接请求,并创建一个新的进程或线程用于处理这个连接。 在服务器程序和客户端程序之间进行数据传输时,需要使用TCP协议提供的套接字接口。服务器程序和客户端程序都可以通过套接字接口创建一个套接字,用于进行数据传输。服务器程序可以使用accept函数来接受连接请求,而客户端程序可以使用connect函数来连接服务器。 一旦连接建立,服务器程序和客户端程序之间就可以通过套接字进行数据传输了。服务器程序可以使用send函数将数据发送给客户端程序,而客户端程序可以使用recv函数接收服务器发送的数据。数据传输结束后,服务器程序和客户端程序都可以使用close函数关闭套接字。 总之,用C 11语言编写基于TCP服务器客户端通信程序需要了解TCP协议、套接字接口和相应的函数,熟练掌握C 11编程语言,并具有相应的开发经验和编程能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值