简单的Tcp服务器

TCP客户端实例程序

文件结构

  • 源代码文件目录(src)

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

  • 头文件目录(include)

    各种.h文件

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

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

  • 项目构建文件(Makefile)

    完成项目的编译

头文件

include/base.h

c++ 复制代码
#ifndef __BASE__H
#define __BASE__H

#define BUFFSIZE    64

#endif

TCP服务器端

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

src/main.cpp

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

c++ 复制代码
#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

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可以去掉执行的文件

运行结果

服务端一次可以多个监听,但是只有一个可以通信
等当前客户端退出后,其他客户端可以与之通信,相当于阻塞

相关推荐
七夜zippoe39 分钟前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥1 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
会员源码网1 小时前
理财源码开发:单语言深耕还是多语言融合?看完这篇不踩坑
网络·个人开发
米羊1212 小时前
已有安全措施确认(上)
大数据·网络
Fcy6482 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满2 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
主机哥哥3 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
ManThink Technology3 小时前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
珠海西格电力科技4 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
QT.qtqtqtqtqt4 小时前
未授权访问漏洞
网络·安全·web安全