读书人

在运行控制台程序的时候按下Ctrl+C程

发布时间: 2012-05-11 12:55:37 作者: rapoo

在运行控制台程序的时候,按下Ctrl+C程序就会马上终止吗?
今天在学习网络的时候发现一个小问题,问题是这样的:
我在控制台下面写了一个UDPServer和一个UDPClient,其中UDPServer只负责recv数据并显示到控制台上,而UDPClient则接受用户的输入并发送到UDPServer。我的问题是,比如我在UDPClient中输入指定条数的数据让程序正常退出,那么程序没有任何问题,但是如果我输入了一条数据以后,按下Ctrl+C强制退出UDPClient,那么之前留在缓冲区里面的数据会被再次发送一遍。
比如说,我在UDPClient里面输入 nihaoma? , UDPServer正确的接受了这条语句并且将它显示出来,这时候我用Ctrl+C退出UDPClient,UDPServer又一次收到了一条 nihaoma? ,请问这是怎么回事?按下Ctrl+C后,它后面的代码也会执行吗?如果执行的话,在怎么样的条件下会执行,怎么样又不执行呢?
附UDPClient在发送那一部分的代码:

C/C++ code
for(i = 0 ; i != dwCount ; ++i)        {            gets(sendbuf);      //按下Ctrl+C的时候,程序应该是阻塞在这一条语句的            ret = sendto(s,sendbuf,dwLength,0,(sockaddr *)&recipent,sizeof(recipent));            printf("sendto message[%d]\n",++times);   //但是这里的语句也被执行了            if(ret == SOCKET_ERROR)            {                printf("sendto() failed with error %d\n",WSAGetLastError());                break;            }            else if(ret == 0)            {                break;            }        }


[解决办法]
你这个问题确实没有碰到过, 不过正常情况下程序不应该用 Ctrl+C去结束, 你应该 判断输入的字符串是不是quit是则推出

在 gets(sendbuf); 这行代码后面添加

if (strcmp(sendbuf, "QUIT"))==0)
{
exit(1);
}
[解决办法]
刚才给你测试了一把, 确实如你所说, ctrl+C后, 往下执行了。
[解决办法]
下断点,仔细查看!
[解决办法]
断电单步调试
[解决办法]
signal Constants
#include <signal.h>

Remarks

The sig argument must be one of the manifest constants listed below (defined in SIGNAL.H).

SIGABRT

Abnormal termination. The default action terminates the calling program with exit code 3.

SIGFPE

Floating-point error, such as overflow, division by zero, or invalid operation. The default action terminates the calling program.

SIGILL

Illegal instruction. The default action terminates the calling program.

SIGINT

CTRL+C interrupt. The default action issues INT 23H.

SIGSEGV

Illegal storage access. The default action terminates the calling program.

SIGTERM

Termination request sent to the program. The default action terminates the calling program.

See Also signal, raise

[解决办法]
C/C++ code
/********************************************************************** FUNCTION: demoSetCtrlHandler(HANDLE hConOut)                       **                                                                    ** PURPOSE: demonstrate SetConsoleCtrlHandler by setting a ctrl+break **          and ctrl+c handler. When the user hits either one of      **          these keys, a message is printed to the console           **          indicating the event.                                     **                                                                    ** INPUT: the output handle to write to                               **********************************************************************/void demoSetCtrlHandler(HANDLE hConOut){  BOOL bSuccess;  setConTitle(__FILE__);  hConsole = hConOut; /* set global console output handle for handler */  myPuts(hConOut, "Let's install a ctrl+c and ctrl+break handler for this\n"                  "process. Hit ctrl+c and ctrl+break a few times to test\n"                  "the handler. Hit enter to return...");  /* set handler for this process */  bSuccess = SetConsoleCtrlHandler(handler_routine, TRUE);  PERR(bSuccess, "SetConsoleCtrlHandler");  /* wait for user to hit enter */  while (myGetchar() != 0xd)    ;  /* now let's generate some control events */  myPuts(hConOut, "Now we'll use GenerateConsoleCtrlEvent to generate a\n"                  "ctrl+c and a ctrl+break event...\n");  bSuccess = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);  PERR(bSuccess, "GenerateConsoleCtrlEvent");  bSuccess = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);  PERR(bSuccess, "GenerateConsoleCtrlEvent");  Sleep(1000); /* give ctrl handle time to output messages */  myPuts(hConOut, "\nNow choose 'Close' then 'Cancel' from the system\n"                  "menu of this console and note that we receive a\n"                  "CTRL_CLOSE_EVENT...\n");  myPuts(hConOut, "\nHit enter to continue...");  myGetchar();  /* remove our handler from the list of handlers */  bSuccess = SetConsoleCtrlHandler(handler_routine, FALSE);  PERR(bSuccess, "SetConsoleCtrlHandler");  return;} 


[解决办法]
以上代码节选自:
console屏幕处理例子程序。终端窗口屏幕处理相关API使用例子。来自MSVC20\SAMPLES\win32\console\
http://download.csdn.net/detail/zhao4zhong1/3461309
[解决办法]
特在此重现莫名其妙隐身的6楼

C/C++ code
/********************************************************************** FUNCTION: demoSetCtrlHandler(HANDLE hConOut)                       **                                                                    ** PURPOSE: demonstrate SetConsoleCtrlHandler by setting a ctrl+break **          and ctrl+c handler. When the user hits either one of      **          these keys, a message is printed to the console           **          indicating the event.                                     **                                                                    ** INPUT: the output handle to write to                               **********************************************************************/void demoSetCtrlHandler(HANDLE hConOut){  BOOL bSuccess;  setConTitle(__FILE__);  hConsole = hConOut; /* set global console output handle for handler */  myPuts(hConOut, "Let's install a ctrl+c and ctrl+break handler for this\n"                  "process. Hit ctrl+c and ctrl+break a few times to test\n"                  "the handler. Hit enter to return...");  /* set handler for this process */  bSuccess = SetConsoleCtrlHandler(handler_routine, TRUE);  PERR(bSuccess, "SetConsoleCtrlHandler");  /* wait for user to hit enter */  while (myGetchar() != 0xd)    ;  /* now let's generate some control events */  myPuts(hConOut, "Now we'll use GenerateConsoleCtrlEvent to generate a\n"                  "ctrl+c and a ctrl+break event...\n");  bSuccess = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);  PERR(bSuccess, "GenerateConsoleCtrlEvent");  bSuccess = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);  PERR(bSuccess, "GenerateConsoleCtrlEvent");  Sleep(1000); /* give ctrl handle time to output messages */  myPuts(hConOut, "\nNow choose 'Close' then 'Cancel' from the system\n"                  "menu of this console and note that we receive a\n"                  "CTRL_CLOSE_EVENT...\n");  myPuts(hConOut, "\nHit enter to continue...");  myGetchar();  /* remove our handler from the list of handlers */  bSuccess = SetConsoleCtrlHandler(handler_routine, FALSE);  PERR(bSuccess, "SetConsoleCtrlHandler");  return;}
[解决办法]
探讨

特在此重现莫名其妙隐身的6楼

[解决办法]
探讨
引用:

特在此重现莫名其妙隐身的6楼

赵老师能不能说一下程序调试的技巧,谢谢!我用的是VS2010

[解决办法]
写了半天我看到是WINDOWS,瞬间什么也不说了,下边是注意到是WINDOWS以前写的。

这个问题我也不懂,我只能猜测一下,可能是信号投递到该线程之后中断了read调用与实际退出动作之间有时间差。

1,gets函数不应该使用,如果你了解一下fgets你自己就怕用gets了,使用fgets取代是第一步。
2,应该判断fgets返回值,如果返回的是NULL,你也要sendto(NULL)吗?
3, Ctrl+C就是向进程kill一个SIGINT信号,我测试过fgets里的read会忽略EINTR继续read,对我没有什么帮助。
4,我见过的服务端,全部都是通过全局变量static volatile sig_atomic_t should_exit配合信号处理函数来检测用户kill信号的,程序需要定时轮询以便检测。
5,最终建议你使用select检测0,设置0非阻塞,并且使用read读取键盘数据,自行根据\n拆行,Ctrl+C信号应当注册信号处理函数,select超时定时检测退出变量是否设置。

读书人网 >C++

热点推荐