我想在服務器和客戶端之間有非阻塞I/O。這兩個連接後,我試圖用fork來處理IO,但是在嘗試讀取「Transport endpoint is not connected」時服務器端發生錯誤,並且它發生了兩次(因爲我猜的是fork) 。簡單套接字非阻塞I/O
Server代碼
//includes taken out
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if(new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
cout<<"\nSuccessful Connection!";
//set nonblock
set_nonblock(new_sd);
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
pid_t pid;
fork();
pid = getpid();
if(pid == 0) {
while(!(out[0] == 'q' && out[1] == 'u' && out[2] == 'i' && out[3] == 't')) {
fgets(out, 255, stdin);
numSent = send(sock, out, strlen(out), 0);
if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
} //end error
} //end while
} //end child
else {
numRead = recv(sock, in, 255, 0);
if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
} //end error
else {
cout<<in;
for(int i=0;i<255;i++)
in[i] = '\0';
} //end else
} //end parent
cout<<"\n\nExiting normally\n";
return 0;
}
客戶端代碼
//包括取出
#define PORT "4950"
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
//set nonblock
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
pid_t pid;
fork();
pid = getpid();
if(pid == 0) {
while(!(out[0] == 'q' && out[1] == 'u' && out[2] == 'i' && out[3] == 't')) {
fgets(out, 255, stdin);
numSent = send(sock, out, strlen(out), 0);
if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
} //end error
} //end while
} //end child process
else {
while(!(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't')) {
numRead = recv(sock, in, 255, 0);
cout<<in;
for(int i=0;i<255;i++)
in[i] = '\0';
}
} //end parent process
cout<<"\n\nExiting normally\n";
return 0;
}
我也使用線程做I/O嘗試。有問題,當我運行程序時,它就像線程不會發生。該程序只是運行「成功連接」,然後「正常退出」。我在while(1)循環中添加了一些cout語句,並且他們打印了幾次,但是由於某種原因它們停止了。我不確定它是否與我的線程或套接字有關。代碼(非常類似於上面),因爲這是在這裏 -
服務器
//includes taken out
#define PORT "4950"
#define STDIN 0
pthread_t readthread;
pthread_t sendthread;
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
struct sockaddr name;
int sock, new_sd;
void* readThread(void* threadid) {
while(1) {
numRead = recv(new_sd, in, 255, 0);
if(numRead > 0) {
cout<<"\n"<<in;
for(int i=0;i<strlen(in);i++)
in[i] = '\0';
} //end if
else if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
}
} //end while
} //END READTHREAD
void* sendThread(void* threadid) {
while(1) {
cin.getline(out, 255);
numSent = send(new_sd, out, 255, 0);
if(numSent > 0) {
for(int i=0;i<strlen(out);i++)
out[i] = '\0';
} //end if
else if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
}
} //end while
} //END SENDTHREAD
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if(new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
cout<<"\nSuccessful Connection!";
//set nonblock
set_nonblock(new_sd);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&readthread, &attr, readThread, (void*)0);
pthread_create(&sendthread, &attr, sendThread, (void*)1);
cout<<"\n\nExiting normally\n";
return 0;
}
客戶
#define PORT "4950"
pthread_t readthread;
pthread_t sendthread;
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
struct sockaddr name;
int sock;
void* readThread(void* threadid) {
while(1) {
numRead = recv(sock, in, 255, 0);
if(numRead > 0) {
cout<<"\n"<<in;
for(int i=0;i<strlen(in);i++)
in[i] = '\0';
} //end if
else if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
}
} //end while
} //END READTHREAD
void* sendThread(void* threadid) {
while(1) {
cin.getline(out, 255);
numSent = send(sock, out, 255, 0);
if(numSent > 0) {
for(int i=0;i<strlen(out);i++)
out[i] = '\0';
} //end if
else if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
}
} //end while
} //END SENDTHREAD
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
//set nonblock
set_nonblock(sock);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&readthread, &attr, readThread, (void*)0);
pthread_create(&sendthread, &attr, sendThread, (void*)1);
cout<<"\n\nExiting normally\n";
return 0;
}
我在很長的帖子道歉,但我一直在這幾天現在,我不知道如何繼續。我嘗試過使用select(),但對於只有1個客戶端和一個服務器I/O來說,這看起來有點多。如果任何人都可以指出上面可能會出現什麼問題或其他提示(或者我只是明確選擇錯誤:)),我將不勝感激。
如果您喜歡閱讀源代碼,請查看node.js項目。他們做得很好,一切都很好記錄。你可以借用一些類似的概念,或者只是採取代碼,這是麻省理工學院。 – tjameson