各种语言写的 tcp echo server

本文详细介绍了如何使用Node.js、Erlang和C++实现一个跨语言的网络服务器,包括服务器创建、事件监听、非阻塞I/O操作及多语言间的通信机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

各个地方找的代码有的没跑过。
代码行数相差很大
nodejs:
var net = require('net');
var server = net.createServer(function (socket) {
  socket.pipe(socket);
});
server.listen(1337, '127.0.0.1');


erlang:
-module(echo_server).
-export([start/0,print/1,stop/0,loop/0]).
 
start()->
    Pid=spawn(echo_server,loop,[]),
    register(sub1,Pid),
    {ok,Pid}.%
 
loop()->
    receive {print,A}->
        io:format("~p.~n",[A]),loop();
        stop -> true end.
 
print(A)->
    sub1 ! {print,A},ok.

stop()->
    sub1 ! stop,ok.

c++ epoll:
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#define INFTIM 1000
#define LOCAL_HOST "192.168.1.100" // 改成你电脑的IP地址

void setnonblocking(int sock)
{
    int opts;
    opts=fcntl(sock,F_GETFL); // 把sock的属性查询出来,存到opts中
    
    if(opts<0)
    {
        perror("fcntl(sock,GETFL)");
        exit(1);
    }
    
    opts = opts | O_NONBLOCK; // 把opts中的某一位O_NONBLOCK置为生效
    
    if(fcntl(sock,F_SETFL,opts)<0) // 再设回去,搞定
    {
        perror("fcntl(sock,SETFL,opts)");
        exit(1);
    }
}


int main()
{
    int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
    ssize_t n;
    char line[MAXLINE];
    socklen_t clilen;
    
    struct epoll_event ev,events[20]; //声明epoll_event结构体的变量, ev用于注册事件, events数组用于回传要处理的事件
    epfd=epoll_create(256); //生成用于处理accept的epoll专用的文件描述符, 指定生成描述符的最大范围为256
    
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    
    setnonblocking(listenfd); //把用于监听的socket设置为非阻塞方式
    
    ev.data.fd=listenfd; //设置与要处理的事件相关的文件描述符
    ev.events=EPOLLIN | EPOLLET; //设置要处理的事件类型和使用的触发器的机制
    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); //把listenfd注册到epfd队列中,监听EPOLLIN事件,使用EPOLLET机制的触发器
    
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    char *local_addr = LOCAL_HOST;
    inet_aton(local_addr,&(serveraddr.sin_addr));
    serveraddr.sin_port=htons(SERV_PORT);
    
    bind(listenfd,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
    
    listen(listenfd, LISTENQ);
    
    maxi = 0;
    
    for( ; ; )
    {
        static int count = 0;
        
        nfds=epoll_wait(epfd,events,20,-1); //等待epoll事件的发生,第四个参数设置为-1,永久阻塞
        printf("[%d] nfds = [%d]\n", ++count, nfds); // 现实当前处于第几次epoll_wait内
        for(i=0; i<nfds; ++i) //处理所发生的所有事件
        {
            if(events[i].data.fd==listenfd)    /**当产生事件的fd和开始监听的fd相同,那么肯定是新客户端请求来了**/
            {
                connfd = accept(listenfd,(struct sockaddr *)&clientaddr, &clilen);
                if(connfd<0)
                {
                    perror("connfd<0");
                    exit(1);
                }
                
                setnonblocking(connfd); //把客户端的socket设置为非阻塞方式
                
                char *str = inet_ntoa(clientaddr.sin_addr);
                printf("connect from %s \n", str);
                
                ev.data.fd=connfd; //设置用于读操作的文件描述符
                ev.events=EPOLLIN | EPOLLET; //设置用于注测的读操作事件
                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //注册ev事件
            }
            else if(events[i].events&EPOLLIN)     /**当这个fd上有读事件发生时**/
            {
                if ( (sockfd = events[i].data.fd) < 0)
                    continue; //因为下面设置了,所以这里考虑了
                
                if ( (n = read(sockfd, line, MAXLINE)) < 0) // 如果read返回值小于零,表示系统调用被中断,要分开考虑错误情况
                {
                    if (errno == ECONNRESET) // 表示连接被重置了,已经无效了,关闭它,删除它
                    {
                        printf("ECONNRESET: %s\n", strerror(ECONNRESET));
                        epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL); // 可以把这个sockfd从epfd队列中删除了
                        close(sockfd);
                    }
                    else // 其他错误
                    {
                        printf("readline error\n");
                    }
                }
                else if (n == 0) // 有读事件触发,但是read返回0,所以是对面已经关闭socketfd了
                {
                    epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL); // 可以把这个sockfd从epfd队列中删除了
                    close(sockfd);
                }
	                {
                    ev.data.fd=sockfd;
                    ev.events=EPOLLOUT | EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); // 下次监听写事件
                }
            }
            else if(events[i].events&EPOLLOUT)    /**当这个fd上有写事件发生时**/
            {
                sockfd = events[i].data.fd;
                write(sockfd, line, n);
                
                ev.data.fd=sockfd;
                ev.events=EPOLLIN | EPOLLET;
                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); //修改sockfd上要处理的事件为EPOLIN,下次监听读事件
            }
        }
    }
} 
待补充。。




好的,以下是用 C 语言 TCP Echo 服务器的简单示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #define MAX_BUFFER_SIZE 1024 #define DEFAULT_PORT 8080 int main(int argc, char *argv[]) { int listen_fd, conn_fd; struct sockaddr_in serv_addr, client_addr; socklen_t client_addr_len; // 创建 TCP 套接字 listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { perror("Error creating socket"); exit(EXIT_FAILURE); } // 初始化服务器地址和端口 memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(DEFAULT_PORT); // 绑定服务器地址和端口 if (bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Error binding"); exit(EXIT_FAILURE); } // 监听连接请求 if (listen(listen_fd, 10) < 0) { perror("Error listening"); exit(EXIT_FAILURE); } printf("Server listening on port %d...\n", DEFAULT_PORT); while (1) { // 接受连接请求 client_addr_len = sizeof(client_addr); conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len); if (conn_fd < 0) { perror("Error accepting"); continue; } printf("Connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 接收客户端数据并回显 char buffer[MAX_BUFFER_SIZE]; int len; while ((len = recv(conn_fd, buffer, MAX_BUFFER_SIZE, 0)) > 0) { send(conn_fd, buffer, len, 0); printf("%s", buffer); // 输出日志 } // 关闭连接 close(conn_fd); } return 0; } ``` 这个程序会在默认端口 8080 上监听连接请求,并接受接收到的任何数据并回显。你可以利用 telnet 或任何网络工具来测试此服务器。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值