gpt4 book ai didi

C++ 多客户端 TCP 服务器

转载 作者:可可西里 更新时间:2023-11-01 02:37:03 31 4
gpt4 key购买 nike

我想用 C++ 编写一个带有 TCP 协议(protocol)的服务器和客户端程序。服务器必须能够同时处理多个客户端。但问题是,例如,在启动服务器后,我以服务器的 IP 地址和端口作为参数运行 2 个客户端。接下来,两个客户端都向服务器发送数据。起初,两个客户端都可以向服务器发送数据,并且服务器能够读取数据。但是,一旦服务器从第二个客户端接收到数据,它似乎就停止了从第一个客户端接收数据。你有什么解决办法吗?

这是服务器代码

using namespace std;

void *task1(void *);

static int connFd;
void error(const char *msg)
{
perror(msg);
exit(1);
}

int main(int argc, char* argv[])
{
int pId, portNo, listenFd;
socklen_t len; //store size of the address
bool loop = false;
struct sockaddr_in svrAdd, clntAdd;

pthread_t threadA[3];

if (argc < 2)
{
cerr << "Syntam : ./server <port>" << endl;
return 0;
}

portNo = atoi(argv[1]);

if((portNo > 65535) || (portNo < 2000))
{
cerr << "Please enter a port number between 2000 - 65535" << endl;
return 0;
}

//create socket
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}

bzero((char*) &svrAdd, sizeof(svrAdd));

svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);

//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
cerr << "Cannot bind" << endl;
return 0;
}

listen(listenFd, 5);

int noThread = 0;

while (noThread < 3)
{
socklen_t len = sizeof(clntAdd);
cout << "Listening" << endl;

//this is where client connects. svr will hang in this mode until client conn
connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);

if (connFd < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
cout << "Connection successful" << endl;
}

pthread_create(&threadA[noThread], NULL, task1, NULL);

noThread++;
}

for(int i = 0; i < 3; i++)
{
pthread_join(threadA[i], NULL);
}
}

void *task1 (void *dummyPt)
{
cout << "Thread No: " << pthread_self() << endl;
char test[256];
bzero(test, 256);
bool loop = false;
while(!loop)
{
bzero(test, 256);
int n = read(connFd, test, 255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",test);
}
cout << "\nClosing thread and conn" << endl;
close(connFd);
}

和客户端代码

using namespace std;

int main (int argc, char* argv[])
{
int listenFd, portNo;
bool loop = false;
struct sockaddr_in svrAdd;
struct hostent *server;

if(argc < 3)
{
cerr<<"Syntax : ./client <host name> <port>"<<endl;
return 0;
}

portNo = atoi(argv[2]);

if((portNo > 65535) || (portNo < 2000))
{
cerr<<"Please enter port number between 2000 - 65535"<<endl;
return 0;
}

//create client skt
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}

server = gethostbyname(argv[1]);

if(server == NULL)
{
cerr << "Host does not exist" << endl;
return 0;
}

bzero((char *) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;

bcopy((char *) server -> h_addr, (char *) &svrAdd.sin_addr.s_addr, server -> h_length);

svrAdd.sin_port = htons(portNo);

int checker = connect(listenFd,(struct sockaddr *) &svrAdd, sizeof(svrAdd));

if (checker < 0)
{
cerr << "Cannot connect!" << endl;
return 0;
}

//send stuff to server
for(;;)
{
char s[300];
//cin.clear();
//cin.ignore(256, '\n');
cout << "Enter stuff: ";
bzero(s, 300);
cin.getline(s, 300);

write(listenFd, s, strlen(s));
}
}

最佳答案

Yor connFd 是一个全局变量,您可以从主线程和所有处理线程访问它。这不行!想象一下 - 您已经接受了第一个连接并将变量设置为接收套接字。您已经生成处理线程,该线程开始读取。接下来你知道,另一个连接即将到来,你也正在接收它!就在此时 connFd 指向新的连接,所以已经在使用它的线程会突然切换到新的连接!当然不好。

解决此问题的方法是以不跨线程共享的方式将连接传递给线程。最简单的方法是使用 C++ 线程类。

例如,这是说明上述想法的代码片段:

void handle_connection(int fd) {
... <your task1 code>
}

...
std::vector<std::thread> threads;
...
int conn = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
threads.push_back(std::thread(&handle_connection, conn));
...

... (in the end)
for (auto&& t : threads)
t.join();

关于C++ 多客户端 TCP 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33922962/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com