我对C:中的Telnet / TCP套接字编程有几个问题:
当我激活客户端以远程访问程序时,它表现正常但是如果我在程序运行时关闭终端,则发出的最后一个远程命令决定重复,直到程序终止,怎么办顶一下?
当我的程序到达套接字代码,即下面我声明的函数时,即使我没有打开客户端,我也无法再手动/本地操作我的程序。我有一个谷歌有这个问题,最好的结果似乎是与接受套接字命令阻止访问。注意:我曾尝试使用非阻塞套接字,但仍然没有运气。另请注意,即使远程终端被激活,我希望我的程序能够同时手动/本地操作,如果可能的话,如果远程终端启动时手动控制程序以反映远程终端的变化
最后,我希望能够输入一个单词或短语来激活命令,而不仅仅是单个字符。如果我输入一个单词而不是一个字符,我会得到一个多字符错误,如果我尝试双引号,它似乎没有响应任何事情,尽管成功编译。根据我所听到的,如果您使用C ++编程而不是C编程,则可以使用双引号,但是我听说可以使用单词在C中发出命令。
我在下面发布了我的套接字代码,我知道while(1)循环是一个问题,但这是目前唯一阻止它关闭连接的东西。另请注意,remotecommand函数在我的主程序中以无限循环的形式声明,但在运行声明的函数后,尽管关闭了连接,但没有运行任何代码。
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// 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 sockfd, new_fd; // listen on sock_fd, new connection on new_fd
int rc;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
char recv_client_msg[100];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop throui_pgh all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->arotocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
int RemoteCommand(){ // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
return(-1);
}
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
//fcntl(new_fd, F_SETFL, O_NONBLOCK);
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
while(1)
{
rc = read(new_fd, recv_client_msg, sizeof(recv_client_msg));
if(write(new_fd,recv_client_msg, rc) <0 ) { printf("error writing to stream socket\n"); }
if(recv_client_msg[0]=='1') {commandSwitch(1,1);}
if(recv_client_msg[0]=='2') {commandSwitch(1,2);}
if(recv_client_msg[0]=='3') {commandSwitch(2,1);}
if(recv_client_msg[0]=='4') {commandSwitch(2,2);}
}
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
return(0);
}
//end of socket setup
这是我第一次使用套接字,所以如果有人有解决方案,请尝试详细说明你的意思。
答案 0 :(得分:3)
您需要实际检查read
返回的内容。它会在出现错误时返回-1
,并在正常关闭连接时返回0
。
由于您没有检查,您不会注意到连接已关闭或任何错误,只是尝试接收和接收,没有任何事情发生并一遍又一遍地使用相同的数据
正确处理的例子:
rc = read(...);
// At this point, we don't know if we have actually received anything
if (rc <= 0)
{
if (rc == 0)
printf("Connection closed in a nice way by the other end\n");
else
fprintf(stderr, "Error reading: %s\n", strerror(errno));
// Do note that not *all* errors are actually fatal,
// For example: If you have non-blocking sockets then you
// could have `errno == EWOULDBLOCK` and that's okay, and
// means you should try to receive again in a little while
break; // Break out of loop, let the connection be closed
}
// Now we *know* we have received something, process the data received
// To be more precise, we have received `rc` byes of data