c - UNIX 中 C++ 和 C 语言的简单 echo 服务器

标签 c unix client echo echo-server

我编写了一个服务器,它从客户端获取消息并用其字典中的单词(我的文件中的字典)来响应它们。例如:

Client wrote: cat
Server got: cat, Server wrote: miauuu! (and client can see the massege 
from server in his window)

我的 dict.txt 文件如下所示:

cat
miauuu!
dog
raw,raw!
etc...

我的代码有一些问题,因为我的服务器从客户端获取消息,但向客户端发送消息仍然存在问题...(在我的客户端窗口中,我看不到来自服务器的消息)。作为客户端,我使用 telnet。有什么想法吗?

我的意思是,我运行我的服务器:./server 9999 和 telnet:telnet 127.0.0.1 9999 并可以向服务器发送消息(服务器可以看到它们),但在 telnet 端我看不到来自服务器的任何消息(也服务器似乎发送了一个空字符串(或者什么都没有,我真的不知道))

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <map>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;

map <string, string> dict;

void* clients_service(void * arg)
{
    int client_fd = *((int*)&arg), buffsize = 1024, bytes_num = 0;
    char buffer[1024];
    char word[1024];

    while(1)
        {
            if ((bytes_num = read(client_fd, buffer, buffsize)) == -1)
            {
                perror("read error");
                exit(1);
            }
            else if (bytes_num == 0)
            {
                fprintf(stdout, "connection closed.\n");
                break;
            }

            buffer[bytes_num] = '\0';
            fprintf(stdout, "Got: %s", buffer);
            string from_client(buffer);
            string to_client = dict[from_client];

            char buff[1024];

            strncpy(buff, to_client.c_str(), strlen(buff));
            buff[strlen(buff) - 1] = '\0';

            if ((write(client_fd, buff, strlen(buff))) == -1)
            {
                fprintf(stderr, "write error\n");
                close(client_fd);
                break;
            }

            fprintf(stdout, "I wrote: %s", buff);

        }
        close(client_fd);
}

void loadDictionary(map <string, string> &dict)
{
    dict.clear();
    ifstream file("dict.txt");
    string s1, s2;

    if(file.is_open())
    {
        while(file.good())
        {
            getline(file, s1);
            getline(file, s2);
            dict.insert(pair<string, string>(s1, s2));
        }
    }

    file.close();
}

int main(int argc, char **argv)
{
    int server_soc_fd, port, buffsize = 1024;
    char buffer[buffsize];
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    loadDictionary(dict);

    if (argc < 2)
    {
        fprintf(stderr, "Use : ./server {port number}\n");
        exit(1);
    }

    port = atoi(argv[1]);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    server_soc_fd = socket(AF_INET, SOCK_STREAM, 0);

    if(server_soc_fd < 0)
    {
        perror("socket");
        exit(1);
    }

    if(bind(server_soc_fd,(struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind");
        exit(1);
    }

    if(listen(server_soc_fd, 10) < 0)
    {
        perror("listen");
        exit(1);
    }

    fprintf(stdout, "\nWorking...\n\n");

    while(true)
    {
        int client_soc_fd = accept(server_soc_fd, NULL, NULL);
        pthread_t thread;
        pthread_create(&thread, NULL, clients_service, (void*)client_soc_fd);
    }

    return 0;
}

最佳答案

这个:

char buff[1024];

strncpy(buff, to_client.c_str(), strlen(buff));
buff[strlen(buff) - 1] = '\0';

不会填充buff

char *strncpy(char *dest, const char *src, size_t n);

n 个字节从 src 复制到 dest

所以你最好这样做:

const char * cstr = to_client.c_str();
size_t len = strlen(cstr);
strncpy(buff, cstr, max(len, sizeof(buff)-1));
buff[len] = 0;

或者更好的是:

const char * cstr = to_client.c_str();
size_t len = strlen(cstr);
if (!len)
  continue;

if ((write(client_fd, cstr, len) == -1)
{
  ...

此外,您不应依赖 write() 一次性写入所有数据。

所以你可以扩展它,像这样:

...
const char * cstr = to_client.c_str();
size_t len = strlen(cstr);

size_t lenWrittenTotal = 0;
while (lenWrittenTotal < len);
{
  ssize_t lenWritten = write(client_fd, cstr + lenWrittenTotal , len - lenWrittenTotal);

  if (lenWritten < 0)
  {
    perror("write");
    break;
  } 
  else if (lenWritten > 0)
  {
    lenWrittenTotal += lenWritten;
  }
  else
  {
    ... 
    break;
  }
};
...

关于c - UNIX 中 C++ 和 C 语言的简单 echo 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13331776/

相关文章:

linux - 如何查找倒数第二个命令的退出状态?

perl - 客户端浏览器关闭时中断服务器端 perl CGI 脚本

arrays - C 中 char ** 和 char (*)[100] 有什么区别?

C#定义奇怪的输出

c++ - 我可以使用 i++ 语法将 int i 增加一个以上吗?

unix - Powershell 是否向后兼容标准命令提示符?

c - 确定使用recv读取的字节数

r - 安装 R 包。包含目录为空。开发 header

c - 如何在C中的recv中插入换行符

java - TCP/IP 客户端 : best way to read multiple inputstreams from server