要學習使用TCP的套接字編程,我正在製作一個簡單的服務器和客戶端。客戶端將發送文件塊,服務器將讀取它們並寫入文件。客戶端和服務器在沒有任何多處理的情況下正常工作。我想要讓多個客戶端可以同時連接。我想給每個連接的客戶端一個唯一的ID,稱爲「client_id」。這是1到n之間的數字。爲每個子進程分配一個帶有分叉的唯一ID
我試圖使用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。文件)
2)連接的客戶端2,傳輸文件中,斷開客戶端2(2.文件)
3)連接的客戶端1,傳輸文件中,斷開的客戶端1(3.file)
4)連接的客戶端1,傳輸文件,斷開客戶端1(4.file)
5)連接客戶端2,傳輸文件,disconnectc牛逼客戶端2(5.file)
6)連接的客戶端2,傳輸文件,斷開客戶端2(6.file)
此'std :: cout <<'語法不是C,將標記更改爲C++ –
不會使用std :: string,std :: ostream等指示更多的C++。程序?另外進程與線程不一樣 – infixed
不確定這是否是原因,但是您應該在子進程中關閉(sockfd)。 – dbush