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

运行结果

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

相关推荐
秃头菜狗1 分钟前
各个主要目录的功能 / Linux 常见指令
linux·运维·服务器
利刃大大2 分钟前
【在线五子棋对战】二、websocket && 服务器搭建
服务器·c++·websocket·网络协议·项目
国科安芯29 分钟前
抗辐照MCU在卫星载荷电机控制器中的实践探索
网络·嵌入式硬件·硬件工程·智能硬件·空间计算
vfvfb34 分钟前
bat批量去掉本文件夹中的文件扩展名
服务器·windows·批处理·删除扩展名·bat技巧
EasyDSS2 小时前
国标GB28181设备管理软件EasyGBS远程视频监控方案助力高效安全运营
网络·人工智能
玩转4G物联网2 小时前
零基础玩转物联网-串口转以太网模块如何快速实现与TCP服务器通信
服务器·网络·物联网·网络协议·tcp/ip·http·fs100p
派阿喵搞电子2 小时前
Ubuntu下有关UDP网络通信的指令
linux·服务器·网络
程序员JerrySUN2 小时前
全面理解 Linux 内核性能问题:分类、实战与调优策略
java·linux·运维·服务器·单片机
Theodore_10222 小时前
大数据(2) 大数据处理架构Hadoop
大数据·服务器·hadoop·分布式·ubuntu·架构
huangyuchi.3 小时前
【Linux】LInux下第一个程序:进度条
linux·运维·服务器·笔记·进度条·c/c++