Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录

  • Tcp协议
  • Tcp协议常见API接口
    • 1. int socket(int domain, int type, int protocol);
    • 2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
      • struct sockaddr
    • 3. int listen(int socket, int backlog);
    • 4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
    • 5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);
  • telnet通信
  • 服务器代码
    • 1. 单进程版本
    • 2.多进程版本
    • 3.多线程版本
    • 4. 线程池版本(附加字典功能)
      • Main.cc
      • TcpServer.cpp
      • ThreadPool.hpp
      • Task.hpp
      • log.hpp
      • dictionary.hpp
      • dictionary.txt 字典文本(简易)
  • 客户端代码
  • 翻译效果图

Tcp协议

简单了解一下Tcp协议,他与Udp协议都是传输层协议,而他与Udp协议的区别就是Tcp是有连接、可靠传输并且是面向字节流的一种协议。

Tcp协议常见API接口

前两个接口与Udp协议用法一样,只不过将申请套接字的SOCK_DGRAM改为了面向字节流的SOCK_STREAM。

1. int socket(int domain, int type, int protocol);

创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

参数 int domin :指定要在其中创建套接字的通信域。这里我们使用AF_INET采用IPV4通信域。

参数 int type : 指定要创建的套接字类型。 Tcp协议是采用面向字节流,所以是用SOCK_STREAM。

参数 int protocol :指定与套接字一起使用的特定协议。

返回值: 如果成功则返回创建的socket 文件描述符, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAM, 0);if (socket_fd == -1){exit(1);}

2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);

绑定端口号 (TCP/UDP, 服务器)
参数 int socket 就是使用socket接口函数所创建的那个socket文件描述符。

struct sockaddr

在这里插入图片描述
由于底层有不同的网络协议,所以它们的地址格式并不相同,所以通常使用struct sockaddr* 作为参数,然后根据前16位地址类型来确定协议内容。

参数 socklen_t address_len, 结构体sockaddr的长度。
typedef unsigned int socklen_t

返回值: 如果绑定成功则返回0, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAN, 0);if (socket_fd == -1){exit(1);}struct sockaddr_in Server;bzero(&Server, 0);Server.sin_family = AF_INET;Server.sin_addr.s_addr = inet_addr(_ip.c_str()); //?Server.sin_port = htons(_port); //?int n = bind( socket_fd, (const struct sockaddr *)&Server, sizeof(Server));if (n != 0){exit(2);}

3. int listen(int socket, int backlog);

作用:将参数socket套接字用于监听,使其处于listen状态。
参数 backlog 这里暂时不讲,将其设为10左右即可。
返回值:成功则为0,失败则为-1。

代码示例

		int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}

4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);

作用:处于listen状态的网络套接字将持续监听是否有其他网络套接字对本套接字进行链接,该接口函数会阻塞,直到有套接字进行链接,链接成功后将返回一个文件描述符

参数socket:处于listen状态的网络套接字。

参数struct sockaddr *restrict address: 输出型函数,用于保存远端主机的套接字信息。

参数socklen_t *restrict address_len: 输出型参数,用于保存远端主机的套接字的长度。

返回值:成功链接返回一个文件描述符,可对它进行读写操作,失败则返回-1。

5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);

对目标网络套接字发送连接请求,一般适用于客户端去连接服务器。
参数 socket: 本地申请的套接字。
参数const struct sockaddr *address:目标网络套接字的struct sockaddr。
参数socklen_t address_len: 目标网络套接字的struct sockaddr的长度。


telnet通信

telnet是linux中可安装的程序,它是一种基于Tcp协议通信的程序,我们可以使用它来对我们的服务器进行测试。

终端输入该命令

telnet ip[xxx.xxx.xxx.xxx] port[1024+]

如果出现找不到该命令,则是因为你的linux主机没有安装telnet

输入
sudo yum install telnet
安装telnet


使用示例
telnet 127.0.0.1 8888

服务器代码

1. 单进程版本

// version 1 单进程单线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);service(socketfd, client);}}void service(const int socketfd, const struct sockaddr_in client){uint16_t client_port = ntohs(client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信//std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(socketfd, info.c_str(), info.size());}close(socketfd);logMessage(DEBUG, "socketfd: %d closed...", socketfd);}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

该版本缺陷很明显,没办法同时处理多个客户端的数据请求。


2.多进程版本

// version 2 多进程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <wait.h>
const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);int pid = fork();if (pid == 0){if (fork()){// 子进程退出 这样我们的父进程就不需要等service函数执行完才waitpidexit(0);}// 孙子进程close(_listensock);service(socketfd, client);exit(0);}// 父进程close(socketfd);waitpid(pid, nullptr, 0);}}void service(const int socketfd, const struct sockaddr_in client){uint16_t client_port = ntohs(client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信// std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(socketfd, info.c_str(), info.size());}close(socketfd);logMessage(DEBUG, "socketfd: %d closed...", socketfd);}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

缺陷是多进程需要维护的系统资源较多,连接的客户端稍微多点就不行了,简而言之就是多进程占用太大。


3.多线程版本

// version 3 多线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer;class ThreadData
{
public:ThreadData(int fd, struct sockaddr_in client): _socketfd(fd), _client(client){}int _socketfd;struct sockaddr_in _client;
};
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);ThreadData *td = new ThreadData(socketfd, client);pthread_t tid;pthread_create(&tid, nullptr, service, (void *)td);}}static void *service(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);uint16_t client_port = ntohs(td->_client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&(td->_client.sin_addr), ip_buffer, sizeof(td->_client));std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(td->_socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", td->_socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信// std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(td->_socketfd, info.c_str(), info.size());}delete td;return nullptr;}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

相对多进程版本,系统资源维护成本没那么大,也算一种不错的方案。


4. 线程池版本(附加字典功能)

Main.cc

#include <iostream>
#include "TcpServer.hpp"
#include "threadPool.hpp"
#include "Task.hpp"
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[8888-9000]\n"<< std::endl;
}//多线程版Mainint main(int argc, char* argv[]){if(argc != 2){Usage("./TcpServer");return 1;}int port = atoi(argv[1]);TcpServer ts(port);ts.Init();ts.run();return 0;}

TcpServer.cpp

                 //TcpServer.cpp
// version 4 线程池版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include "threadPool.hpp"
#include "Task.hpp"const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer;class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;ThreadPool<Task>::GetInstance()->Start();while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(NORMAL, "accept success..., and get a link, socketfd: %d", socketfd);ThreadPool<Task> *threadpool = ThreadPool<Task>::GetInstance();threadpool->Push(Task(socketfd, client));}}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

ThreadPool.hpp

#pragma once#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>struct ThreadInfo
{pthread_t tid;std::string name;
};static const int defalutnum = 10;template <class T>
class ThreadPool
{
public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void Wakeup(){pthread_cond_signal(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsQueueEmpty(){return tasks_.empty();}std::string GetThreadName(pthread_t tid){for (const auto &ti : threads_){if (ti.tid == tid)return ti.name;}return "None";}public:static void *HandlerTask(void *args){ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);std::string name = tp->GetThreadName(pthread_self());while (true){tp->Lock();while (tp->IsQueueEmpty()){tp->ThreadSleep();}T t = tp->Pop();tp->Unlock();t();}}void Start(){int num = threads_.size();for (int i = 0; i < num; i++){threads_[i].name = "thread-" + std::to_string(i + 1);pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);}}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Push(const T &t){Lock();tasks_.push(t);Wakeup();Unlock();}static ThreadPool<T> *GetInstance(){if (nullptr == tp_) // ???{pthread_mutex_lock(&lock_);if (nullptr == tp_){// std::cout << "log: singleton create done first!" << std::endl;tp_ = new ThreadPool<T>();}pthread_mutex_unlock(&lock_);}return tp_;}private:ThreadPool(int num = defalutnum) : threads_(num){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~ThreadPool(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);}ThreadPool(const ThreadPool<T> &) = delete;const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:std::vector<ThreadInfo> threads_;std::queue<T> tasks_;pthread_mutex_t mutex_;pthread_cond_t cond_;static ThreadPool<T> *tp_;static pthread_mutex_t lock_;
};template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

Task.hpp

#pragma once
#include <functional>
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "dictionary.hpp"Dictionary dictionary;
class Task
{
public:Task(){}Task(int socketfd, const struct sockaddr_in client): _socketfd(socketfd), _client(client){}void operator()(){char key_word[64];while (true){memset(key_word, 0, sizeof key_word);int n = read(_socketfd, key_word, sizeof key_word - 1);if (n == 0){logMessage(NORMAL, "Connection closed by foreign host, socketfd[%d] closed...", _socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (key_word[n - 1] == '\n'){// 使用telnet通信logMessage(DEBUG, "find \\n, telnet connection...");key_word[n - 2] = 0;}else{// 使用客户端通信key_word[n] = 0;}std::string value_word = dictionary.translate(key_word);write(_socketfd, value_word.c_str(), value_word.size());}close(_socketfd);logMessage(DEBUG, "socketfd[%d] closed...", _socketfd);}private:int _socketfd;struct sockaddr_in _client;
};

log.hpp

#pragma once
#include <iostream>
#include <stdarg.h>
#include <string>
#include <time.h>
const char *levels[] = {"NORMAL","WARNING","ERROR","FATAL","DEBUG"};#define NORMAL 0
#define WARNING 1
#define ERROR 2
#define FATAL 3
#define DEBUG 4void logMessage(int level, const char *format, ...)
{
#ifndef debugif (level == DEBUG){return;}
#endifchar stdBuffer[1024];time_t now = time(nullptr);struct tm *lt = localtime(&now);snprintf(stdBuffer, sizeof stdBuffer, "[%s][%d:%d]: ", levels[level], lt->tm_hour, lt->tm_min);char logBuffer[1024];va_list va;va_start(va, format);vsnprintf(logBuffer, sizeof logBuffer, format, va);printf("%s%s\n", stdBuffer, logBuffer);
}

dictionary.hpp

#pragma once
#include <unordered_map>
#include <string>
#include <iostream>
#include <fstream>const char separator = ':';class Dictionary
{
public:Dictionary(){Init();}bool split(const std::string &dword, std::string &part1, std::string &part2){int pos = dword.find(separator, 0);if (pos == std::string::npos){return false;}part1 = dword.substr(0, pos);part2 = dword.substr(pos + 1);}void Init(){std::ifstream in("dictionary.txt");std::string dword;while (std::getline(in, dword)){std::string part1;std::string part2;if (split(dword, part1, part2))_dic[part1] = part2;}in.close();}std::string translate(std::string key){auto it = _dic.find(key);if (it == _dic.end()){return "word unknow";}return it->second;}private:std::unordered_map<std::string, std::string> _dic;
};

dictionary.txt 字典文本(简易)

apple:苹果...
banana:香蕉...
red:红色...
yellow:黄色...
the: 这
be: 是
to: 朝向//对
and: 和
I: 我
in:...里
that: 那个
have: 有
will:for: 为了
but: 但是
as:...一样
what: 什么
so: 因此
he: 他
her: 她
his: 他的
they: 他们
we: 我们
their: 他们的
his: 它的
with:...一起
she: 她
he: 他
it:

客户端代码

客户端代码仅此一套 且可适配服务器四个版本

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
// telnet server_ip server_port
void Usage(const std::string &proc)
{std::cout << "\n\rUsage: " << proc << " ip[xxx.xxx.xxx.xxx] port[8888-9000]\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 3){Usage("./TcpClient");exit(1);}// 申请socketint socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd < 0){logMessage(FATAL, "socket create failed...");exit(2);}// 初始化结构体sockaddrstruct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);if (connect(socketfd, (const sockaddr *)&server, sizeof server) < 0){// connect失败logMessage(FATAL, "connect create failed...");exit(3);}// connect 成功logMessage(DEBUG, "connect create seccess...");// 开始发送和读取数据std::string out_buffer;char in_buffer[1024];while (true){memset(in_buffer, 0, sizeof in_buffer);std::cout << "Send a Message@ ";std::getline(std::cin, out_buffer);write(socketfd, out_buffer.c_str(), out_buffer.size());int n = read(socketfd, in_buffer, sizeof in_buffer - 1);if (n > 0){in_buffer[n] = 0;std::cout << "Server echo Message: " << in_buffer << std::endl;}else if (n == 0){logMessage(WARNING, "Connection closed by foreign host, socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}}close(socketfd);return 0;
}

翻译效果图

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/20137.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——如何保证 TCP 传输的可靠性

TCP 是传输层上的协议&#xff0c;它是可靠的&#xff0c;面向连接的。 概括 1. 设置传输格式&#xff0c;包括分为 TCP 段、使用校验和、使用序列号 2. 数据丢失之后的重传&#xff0c;超时重传、快速重传、SACK 选择确认、D-SACK 重复选择确认 3. 流量控制&#xff0c;控…

字符串-至多包含K种字符的子串中最长子串(mid)

一、题目描述 二、解题思路 借鉴以下题目思想&#xff0c;使用双指针&#xff0c;外层循环右侧指针移动&#xff0c;内存循环左侧指针移动 字符串-最长不含重复字符的子字符串(mid)-CSDN博客文章浏览阅读622次&#xff0c;点赞17次&#xff0c;收藏4次。java刷题&#xff1a;…

探索第三方美颜SDK:美颜插件的技术原理

本篇文章&#xff0c;我们将深入了解第三方美颜SDK&#xff0c;主要探讨关于美颜插件的工作机制与算法。 一、第三方美颜SDK的概述 第三方美颜SDK是由专业团队开发的一套用于实现美颜功能的软件开发工具包。它通常包括了各种美颜算法、滤镜效果、人脸识别等核心技术&#xff…

Kafka broker的新增和剔除(服役与退役)

说明&#xff1a;集群现有broker:node1,node2,node3三个,broker.id分别为0&#xff0c;1&#xff0c;2 已有两个topic&#xff1a;products、cities 1、退役&#xff08;Kafka集群中减少一个服务器broker2&#xff09; 退役后要保证剩下的服务器数量大于等于备份数&#xff0c…

软件设计不是CRUD(21):在流式数据处理系统中进行业务抽象落地——需求分析

本文主要介绍如何在数据处理系统中应用业务抽象的设计思想。目前业界流行的数据处理方式是流式处理&#xff0c;主流的流式处理引擎有Apache Spark&#xff0c;Apache Flink等等。本文选择Apache Flink作为实战案例的落地。由于本文主要是讲解设计思想和流式处理引擎相结合的方…

排八字软件有哪些?

排八字软件有哪些&#xff1f;在市面上有很多排八字的软件可供选择&#xff0c;其中一些比较知名的有&#xff1a; 无敌八字排盘软件&#xff1a;这是一款功能强大的八字排盘软件&#xff0c;提供详细的八字解析和命理分析服务&#xff0c;且完全免费。 网易星盘&#xff1a;网…

【一百】【算法分析与设计】N皇后问题常规解法+位运算解法

N皇后问题 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 给出一个nnn\times nnn的国际象棋棋盘&#xff0c;你需要在棋盘中摆放nnn个皇后&#xff0c;使得任意两个皇后之间不能互相攻击。具体来说&#xff0c;不能存在两个皇后位于同…

自用了很久的一款强制卸载软件,超级好用!!!

Ashampoo UnInstaller是一款由Ashampoo公司开发的专业卸载工具&#xff0c;它提供了比Windows自带卸载功能更为彻底的程序卸载解决方案。是一款功能强大的卸载工具&#xff0c;旨在帮助用户彻底删除不需要的程序和应用&#xff0c;卸载难以卸载的软件工具&#xff0c;此外他还有…

面试杂谈k8s

其实看我之前的博客&#xff0c;k8s刚有点苗头的时候我就研究过&#xff0c;然后工作的时候间接接触 也自己玩过 但是用的不多就忘记了&#xff0c;正苦于不知道写什么&#xff0c;水一篇 用来面试应该是够了 支持云应用开发、运行与运维一体化的云应用平台软件应运而生 k8s核…

智慧车站管理:提升地铁站新质生产力的策略

应用图扑自研产品 HT for Web 结合 BIM 技术&#xff0c;搭建轻量化的 WebGIS 智慧车站系统。 该系统通过整合轨道交通信息&#xff0c;实现了车站数据的多维互联与融合。提升了车站信息管理效率和运营效能&#xff0c;并优化了乘客出行体验。对构建智能、高效、环保的轨道交通…

使用C#实现VS窗体应用——画图板

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。&#x1f34e;个人主页&#xff1a;Meteors.的博客&#x1f49e;当前专栏&#xff1a;小项目✨特色专栏&#xff1a; 知识分享&#x1f96d…

前端树形结构组件的设计与实现:以企查查、天眼查股权结构为例

摘要 随着信息化时代的不断发展&#xff0c;数据可视化在各行各业的应用越来越广泛。特别是在商业信息查询领域&#xff0c;如企查查、天眼查等平台&#xff0c;通过直观的数据展示方式&#xff0c;帮助用户快速理解复杂的商业关系。本文将以一个前端tree树形结构模版组件为例…

【算法】模拟算法——替换所有的问号(easy)

题解&#xff1a;替换所有的问好(模拟算法) 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 纯模拟。从前往后遍历整个字符串&#xff0c;找到问号之后&#xff0c;就⽤ a ~ z 的每⼀个字符去尝试替换即可。 3.参考代码 class Solution { pu…

使用docker部署项目

一、docker私有镜像仓库 1、docker私有镜像仓库 库&#xff08;Repository&#xff09;是集中存放镜像的地方&#xff0c;又分为公共镜像和私有仓库。 当我们执行docker pull xxx的时候&#xff0c;它实际上是从registry.docker.com这个地址去查找&#xff0c;这就是Docker公…

城市之旅:使用 LLM 和 Elasticsearch 简化地理空间搜索(二)

我们在之前的文章 “城市之旅&#xff1a;使用 LLM 和 Elasticsearch 简化地理空间搜索&#xff08;一&#xff09;”&#xff0c;在今天的练习中&#xff0c;我将使用本地部署来做那里面的 Jupyter notebook。 安装 Elasticsearch 及 Kibana 如果你还没有安装好自己的 Elasti…

EitbaseEX香港业务开展,提升用户友好交易体验

在全球范围内备受瞩目的加密货币交易平台Coinbase&#xff0c;宣布正式入驻香港市场&#xff0c;并命名为EitbaseEX。这一战略性扩展举措&#xff0c;旨在为香港提供先进的加密货币交易技术和服务&#xff0c;同时将香港打造为其在亚太地区的重要枢纽。 作为国际金融中心&#…

Nginx 文件下载 限速设置 限制访问频率 下载速率 并发连接数 简单实用教程

1 没有限速之前 2 nginx配置 #增加如下配置 limit_conn_zone $binary_remote_addr zoneaddr:10m; location / {limit_conn addr 1; #按照来源&#xff0c;限制每个IP 的连接数为1limit_rate_after 1000k;不限速下载的数据量limit_rate 100k; #限制最大传输速率root /data/log…

sudo命令的隐患-要注意安全使用!!严格管理!!严格控制

前言 众所周知&#xff0c;sudo命令非常方便&#xff0c;而且有一定的优点。比如不需要知道root密码就可以执行一些root的命令。相比于su 必须知道root密码来说&#xff0c;减少了root密码泄露的风险。 但是sudo也是一把非常锋利的双刃剑&#xff0c;需要加以限制&#xff0c;…

翻译《The Old New Thing》- What a drag: Dragging a virtual file (IStream edition)

What a drag: Dragging a virtual file (IStream edition) - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20080319-00/?p23073 Raymond Chen 2008年03月19日 拖拽虚拟文件&#xff08;IStream 版本&#xff09; 上一次&#xff0c;我们看…

python | 类的实现

和实例有关的&#xff0c;通过对象名&#xff0c;打点调用 实例属性&#xff0c;实例方法 stuStudent("XiaoMing",18) print(stu.name) 类属性、静态方法和类方法都是通过类名直接调用 Student.name 静态方法和类方法都不能调用实例属性和实例方法 动态绑定 如果是函…