【发布时间】:2017-04-18 18:34:33
【问题描述】:
为了学习使用 TCP 进行套接字编程,我正在制作一个简单的服务器和客户端。客户端将发送文件块,服务器将读取它们并写入文件。客户端和服务器在没有任何多处理的情况下正常工作。我想让它让多个客户端可以同时连接。我想给每个连接的客户端一个唯一的 id,称为“client_id”。这是一个介于 1 和 n 之间的数字。
我尝试使用 fork() 来生成子进程,在子进程中我接受连接,然后读入数据并将其保存到文件中。但是,client_id 变量不会跨进程同步,因此有时会增加,有时不会。我不完全明白发生了什么。 client_id 的值永远不应重复,但有时我会看到数字出现两次。我相信这是因为在分叉时,子进程会获得父进程所有内容的副本,但并行进程之间没有同步。
这是我等待连接客户端的无限循环。在子进程中,我在另一个无限循环中传输文件,该循环在 recv 接收到 0 字节时终止。
int client_id = 0;
while(1){
// accept a new connection
struct sockaddr_in clientAddr;
socklen_t clientAddrSize = sizeof(clientAddr);
//socket file descriptor to use for the connection
int clientSockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &clientAddrSize);
if (clientSockfd == -1) {
perror("accept");
return 4;
}
else{ //handle forking
client_id++;
std::cout<<"Client id: "<<client_id<<std::endl;
pid_t pid = fork();
if(pid == 0){
//child process
std::string client_idstr = std::to_string(client_id);
char ipstr[INET_ADDRSTRLEN] = {'\0'};
inet_ntop(clientAddr.sin_family, &clientAddr.sin_addr, ipstr, sizeof(ipstr));
std::string connection_id = std::to_string(ntohs(clientAddr.sin_port));
std::cout << "Accept a connection from: " << ipstr << ":" << client_idstr
<< std::endl;
// read/write data from/into the connection
char buf[S_BUFSIZE] = {0};
std::stringstream ss;
//Create file stream
std::ofstream file_to_save;
FILE *pFile;
std::string write_dir = filedir+"/" + client_idstr + ".file";
std::string write_type = "wb";
pFile = fopen(write_dir.c_str(), write_type.c_str());
std::cout<<"write dir: "<<write_dir<<std::endl;
while (1) {
memset(buf, '\0', sizeof(buf));
int rec_value = recv(clientSockfd, buf, S_BUFSIZE, 0);
if (rec_value == -1) {
perror("recv");
return 5;
}else if(rec_value == 0){
//end of transmission, exit the loop
break;
}
fwrite(buf, sizeof(char), rec_value, pFile);
}
fclose(pFile);
close(clientSockfd);
}
else if(pid > 0){
//parent process
continue;
}else{
perror("failed to create multiple new threads");
exit(-1);
}
}
}
这是我执行以下操作时的服务器输出,括号中是预期的文件名(client_id.file):
1) 连接客户端 1,传输文件,断开客户端 1 (1.file)
2)连接客户端2,传输文件,断开客户端2(2.file)
3)连接客户端1,传输文件,断开客户端1(3.file)
4)连接客户端1,传输文件,断开客户端1(4.file)
5)连接客户端2,传输文件,断开客户端2(5.file)
6)连接客户端2,传输文件,断开客户端2(6.file)
【问题讨论】:
-
这个
std::cout<<的语法不是C,把标签改成C++ -
不会使用 std::string、std::ostream 等表示更多的 C++ 。程序?进程与线程也不一样
-
不确定是否是这个原因,但您应该在子进程中
close(sockfd);。 -
@infixed 好点。更改了措辞。
-
@dbush 没有修复它。
标签: c++ multithreading sockets