当前位置: 首页 > article >正文

简单的Tcp服务器

TCP客户端实例程序

文件结构

  • 源代码文件目录(src)

    这里有main.cpp,是服务器端程序

  • 头文件目录(include)

    各种.h文件

  • 实例程序文件目录(test)

    这里写一个客户端连接程序

  • 项目构建文件(Makefile)

    完成项目的编译

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

头文件

include/base.h

#ifndef __BASE__H
#define __BASE__H

#define BUFFSIZE    64

#endif

TCP服务器端

网络编程的主要内容其实就是在服务器端,要实现最基础的 TCP 服务器

src/main.cpp

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>
#include "base.h"
using namespace std;
// 错误处理函数
static void error_handle(string opt,string message){
    perror(opt.c_str());
    cout << message << endl;
    exit(1);
}
int main(int argc, char *argv[]){//argc是参数个数
    //参数需要2个:运行文件+端口
    if(argc < 2){       
        cout << "less" << argv[0] << "port" << endl;
        exit(1);                        
    }
    //创建套接字
    int serve_sock = socket(PF_INET, SOCK_STREAM, 0);   
    if(serve_sock==-1){
        error_handle("socket", "socket() error");
    }
    //绑定地址
    struct sockaddr_in serve_addr;
    serve_addr.sin_family = AF_INET;
    //htonl---host to net long
    //将一个32位的主机字节序变成网络字节序
    serve_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serve_addr.sin_port = htons(atoi(argv[1]));
    //返回指针要传地址,而且要强制类型转换成sockaddr*类型
    int ret = bind(serve_sock, (struct sockaddr *)&serve_addr, sizeof(serve_addr));
    if(ret==-1){
        error_handle("bind", "bind() error");
    }
    //监听
    if(listen(serve_sock,5)==-1){
        error_handle("listen", "listen() error");  
    }
    //accept--接受客户端的请求
    int client_sock;
    struct sockaddr_in client_addr;
    socklen_t client_addr_size=sizeof(client_addr);
    //while(1)循环应答
    while(1){
        client_sock = accept(serve_sock, (struct sockaddr *)&client_addr, &client_addr_size);
        if(client_sock ==-1){
            continue;//接受新的请求
        }
        //接收新的客户端请求,进行客户端数据处理
        //inet_ntoa():将一个网络字节序的IP地址转化为点分十进制的IP地址(字符串)。
        cout << "Accept New Client : " << inet_ntoa(client_addr.sin_addr) << \
                           ", port : " << ntohs(client_addr.sin_port) << std::endl;
        cout << "Start Recv Client Data........." << endl;
        /*传输信息*/
        char message[BUFFSIZE];
        memset((void *)&message, 0, BUFFSIZE);//传指针
        int MessageLen;
        //读取客户端的请求数据
        while((MessageLen=read(client_sock,message,BUFFSIZE))!=0){
            cout << "Server recv from Client:" << message << endl;
            //将消息回传给客户端
            write(client_sock, message, MessageLen);
            //清空消息
            memset(message, 0, BUFFSIZE);
        }
        close(client_sock);
    }
    //服务器关闭
    close(serve_sock);
    return 0;
}
    

客户端

test/tcpClient.cpp

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>
#include "base.h"
using namespace std;
// 出错调用函数
static void error_handle(std::string opt, std::string message)
{
    //根据errno值获取失败原因并打印到终端
    perror(opt.c_str());
    std::cout << message << std::endl;
    exit(1);
}
int main(int argc,char* argv[]){
    if(argc < 3){
        cout << "Input IP and Port!" << endl;
    }
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock==-1){
        error_handle("socket", "socket() error");
    }
    //向服务器请求连接
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));
    int ret =connect(sock,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if(ret==-1){
        error_handle("connect", "connect() error");
    }
    cout << "connect success!!" << endl;
    //数据处理
    char message[BUFFSIZE];
    while (1){
        cout << "Please Input Message(Q to quit) : " << endl;
        cin >> message;
        if((!strcmp(message, "q")) || (!strcmp(message, "Q"))){
            break;
        }
        //把数据发送给服务端
        write(sock,message,strlen(message));
        //读取u服务端回传的消息
        int len = read(sock, message, BUFFSIZE - 1);
        message[len] = 0;
        cout << "echo message:" << message << endl;
    }
    close(sock);
    return 0;
}

Makefile

pwd=${shell pwd}
src_dir=$(pwd)/src/
include_dir=$(pwd)/include/
test_dir=$(pwd)/test/

TARGET=TcpServer
########################## src section #################################
obj_src=${shell find $(src_dir) -name "*.cpp"}
OBJS=${patsubst %.cpp,%.o,$(obj_src)}
#添加测试文件的内容
test_src=${shell find ${test_dir} -name "*.cpp"}
TEST_OBJ=${patsubst %.cpp,%.o,${test_src}}
tests=${patsubst %.cpp,%,${test_src}}
####################### flag section ########################################
GXX=g++
CFLAGS=-I${include_dir}
#############################################################################
$(TARGET): $(OBJS)
	$(GXX) $(CFLAGS)  -o $@ $(OBJS)

%.o:%.cpp
	$(GXX) ${CFLAGS} -c -o $@ $<
#添加编译测试文件的规则使用
.PHONY: test
test: $(tests)
$(tests): $(TEST_OBJ)
	$(GXX) $(CFLAGS)  -o $@ $(TEST_OBJ)

$(TEST_OBJ): $(test_src)
	$(GXX) ${CFLAGS} -c $< -o $@


clean:
	rm $(TARGET)
	rm $(OBJS)
	rm ${TEST_OBJ}
	rm ${tests}

项目编译

注意如果头文件.h和.cpp在同一目录下可直接编译

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果头文件在同一目录文件夹,则必须在编译时指定头文件位置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

😄本项目编译

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在当前目录下make

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在当前目录下make test

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

make clean可以去掉执行的文件

运行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

服务端一次可以多个监听,但是只有一个可以通信

等当前客户端退出后,其他客户端可以与之通信,相当于阻塞


http://www.kler.cn/a/283621.html

相关文章:

  • AI 扩展开发者思维方式:以 SQL 查询优化为例
  • Autosar CP DDS规范导读
  • 超市里的货物架调整(算法解析)|豆包MarsCode AI刷题
  • 【Qt】Macbook M1下载安装
  • java操作ES(一)RestHighLevelClient(2)集成与demo
  • [项目代码] YOLOv5 铁路工人安全帽安全背心识别 [目标检测]
  • 【香橙派系列教程】(十六) 语音模块与阿里云结合
  • Kafka日志及常见问题
  • x-cmd mod | x scoop - Windows 开源包管理工具
  • Java、python、php版 美发美甲预约服务平台 美容院管理系统(源码、调试、LW、开题、PPT)
  • 安卓15发布日期确定,安卓15 谷歌GMS认证截止日期有重大变化!安卓版本GMS认证截止时间更新,谷歌GMS认证之MADA/EDLA设备认证截止时间介绍
  • CSS 的文字平滑属性font-smooth
  • C++研发笔记1——github注册文档
  • C++类和对象(5)——运算符重载(以日期类为例)
  • 数据库,SQL和 MySql的三者关系
  • 智能听诊器:开启宠物健康管理新维度
  • 【网络安全】打开这份“开学礼” 谨防骗子“冲业绩”
  • 【Spring Boot 3】【Web】同时启用 HTTP 和 HTTPS
  • vue3+ts+vite项目代码检查报错(vue-tsc)
  • 解决Nginx负载均衡中的慢启动问题:策略与实践
  • k8s-pod 实战八 (gRPC 探测详细分析)
  • Cpp学习手册-基础学习
  • Python 处理 PDF 文件(PyPDF2, ReportLab)
  • 云轴科技ZStack与鼎甲科技共创数据保护新篇章
  • 显示中文字体问题解决:ImportError: The _imagingft C module is not installed
  • 最简洁!四步完成C#——opencv环境配置