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

运行结果

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

相关推荐
tRNA做科研13 分钟前
Bio-Linux-shell详解-1-从0开始
linux·运维·服务器
老汉忒cpp43 分钟前
TCP全连接队列和tcpdump抓包
网络·tcp/ip·tcpdump
小黑爱编程44 分钟前
【Linux网络】Socket套接字
linux·运维·网络
KookeeyLena71 小时前
udp协议除了打游戏还有什么用途
网络·网络协议·udp
kaixin_啊啊1 小时前
TCP/IP模型成功与OSI模型失败的深层原因:技术、理念与市场化路径的比较
服务器·tcp/ip·php
gs801401 小时前
安装node 报错需要:glibc >= 2.28
linux·服务器·前端·node.js
hgdlip2 小时前
一台电脑对应一个IP地址吗?‌探讨两台电脑共用IP的可能性
服务器·网络协议·tcp/ip·电脑
alsknv4 小时前
IP地址是怎么实现HTTPS访问的?
网络·网络协议·tcp/ip·安全·web安全·http·https
GDAL4 小时前
Puppeteer-Cluster:并行处理网页操作的新利器
运维·服务器·nodehtmltoimage
limengshi1383924 小时前
通信工程学习:什么是GFP通用成帧规范
服务器·网络·网络协议·学习·信息与通信