Member 12330615 Ответов: 2

Как я могу решить свою простую или непростую проблему?


В моем коде VC++ есть две клиентские и серверные программы.

Клиентская программа отправляет Command_info в серверную программу.
Серверная программа отправляет ответный пакет так же, как и Command_info.

Но я могу изменить значение одного поля из Command_info, клиент делает исключения ошибки во время выполнения, такие как в следующем.

Клиентскими источниками являются:

void CForm2000::SendData2SS(int control_code, int net, int input_value, int output_value)
{

struct Command_info {
	int control_code;
	int network;
	int rep_type;	
	unsigned int input_value;
	unsigned int output_value;
	int error_code;
};

Command_info Cmd;

	Cmd.control_code = control_code;
	if (net == 0)
		net = MY_Type;

	Cmd.network = net;
	Cmd.rep_type = REP_REQ;	
	Cmd.input_value = input_value;
	Cmd.output_value = output_value;
	Cmd.error_code = 0;

	int SendSW = 0;

	while (TcpConnectStatus == 0)
		TCPClientOpen();

	while (TcpConnectStatus == 1)
	{
		if (SendSW == 0)
		{
			int retcode = TCPClientSend();
			if (retcode == RESULT_SUCCESS)
				SendSW = 1;
		}

		if (SendSW == 1)
		{
			if (TCPClientRecv() == RESULT_SUCCESS)
			{
				if (Cmd.rep_type == REPLY_OK)
				{
					if (Cmd.error_code == 0)
						AfxMessageBox(_T("OK"));
					else AfxMessageBox(_T("Not OK"));
				}
			}
			else AfxMessageBox(_T("Communication Error"));
			return;
		}
	}
}

В приведенной выше клиентской программе,
Все в порядке, если я установлю значение Cmd.net = 1.
Я получаю от сервера и Cmd.rep_type является "REPLY_OK".

Но когда я изменяю значение Cmd.net = 2,
У меня нет никаких проблем с получением от сервера. Но после показа AfxMessageBox (_T ("OK")) появляется много сообщений об ошибках времени выполнения, включая" ошибку нарушения доступа "и поиск" источника memcpy.asm " - это мой первый опыт работы с сообщениями времени выполнения.

Кто знает причину и как ее исправить?

// Таким образом, вы можете использовать код TCPClientRecv()
int TCPClientRecv()
{	
#define TBUFFER_SIZE 1024

	int ret_code = RESULT_FAIL;
	int error_cnt = 0;
	int retcnt = 0;	

	while (TCP_WORKING_SW == 1)
	{
		TRACE("TCP SOCKET try to recving, RetryCnt = %d\n", ++retcnt);		
		::ZeroMemory(TRecvBuffer, TBUFFER_SIZE);

		TRecv_Size = recvfrom(ClientSocket, TRecvBuffer, TBUFFER_SIZE, 0, (struct sockaddr*) &ToServer, &ToServer_Size);
		if ((TCP_WORKING_SW == 0)) goto EXIT;
		if (TRecv_Size <= 0)
		{
			if (TRecv_Size == -1)
			{		
				if (error_cnt++ > 100)	goto EXIT;
				Sleep(100);

				int ret_code = WSAGetLastError();
				if (ret_code == WSAEWOULDBLOCK)
					;				
				else if (ret_code == WSAECONNABORTED)
						goto EXIT;				
				else if (ret_code == WSAENOTCONN)
						TCPClientOpen();				
				else goto EXIT;				
			}
			else if (TRecv_Size == 0)
			{
				ret_code = RESULT_RESET;
				goto EXIT;
			}
			else
			{
				TRACE("recvfrom() error. Closing SOCKET. TRecv_Size = %d \n", TRecv_Size);
				goto EXIT;
			}
		}
		else {
			TRACE(("TCP Data %d bytes received.\n"), TRecv_Size);
			::ZeroMemory(&Cmd, sizeof(Cmd));
			memcpy(&Cmd, TRecvBuffer, TRecv_Size);			
			return RESULT_SUCCESS;
		}
	}

EXIT:
	TCPClientClose();
	ErrorCode = E_SOCKET_RECEIVE;
	return ret_code;

}//int TCPClientRecv()


PS: Я попытался изменить этот протокол с TCP / IP на файловый ввод-вывод между клиентом и сервером, но потерпел неудачу.
В той же точке и те же сообщения об ошибках во время выполнения отображаются.

Что я уже пробовал:

Еще 1 неделя потрачена впустую на эту проблему.

Jochen Arndt

Ошибка, скорее всего, не в показанном коде (он выглядит нормально). Он может быть расположен в отправляющей или (что более вероятно) принимающей функции.

Нарушение доступа происходит при записи в память, которая не принадлежит приложению. Типичными источниками являются недопустимые указатели или индексы массивов, которые не привязаны. Последний будет перезаписывать другую память, что может привести к нарушениям доступа, когда эта память содержит указатели.

Вы можете обновить свой вопрос с помощью кода TCPClientRecv ().

Richard MacCutchan

Со всеми этими операторами goto трудно быть уверенным, но вы вполне можете пропустить инициализацию указателя. Единственный способ диагностировать это - использовать отладчик для отслеживания кода до точки первой ошибки.

2 Ответов

Рейтинг:
9

Jochen Arndt

Ваш код не показывает соответствующие объявления для используемых переменных. Вам следует избегать использования глобальных переменных (простое имя функции TCPClientRecv() указывает, что это не функция-член класса).

Даже если это функция-член класса, вы должны использовать локальные переменные функции вместо переменных-членов класса, где это возможно.

Примером может служить ваш TRecvBuffer Как это объявляется (с каким размером)? То TBUFFER_SIZE определение находится внутри функции, но переменная, по-видимому, объявлена снаружи (поверх исходного файла или в заголовочном файле), так что она не может использовать это определение. Поскольку буфер используется только внутри функции, он является кандидатом на локальную переменную функции.

Вы определяете struct Command_info и объявить местную Cmd переменная в вашем SendData2SS функция. Как может TCPClientRecv() затем функция получает доступ к этой переменной? Для этого он должен быть передан в качестве аргумента или переменной, а функция должна быть членом класса.

Чтобы прибить его к ногтю:
Представленный здесь код даже не компилировался. Если вы ожидаете помощи, вы должны показать код точно таким, как он есть. Если вам нужно вырезать фрагменты кода, Вы должны предоставить всю информацию о фрагменте, необходимую для воспроизведения того, что сделано. Это особенно относится к объявлениям используемых переменных и обработке динамически выделяемых переменных.


Рейтинг:
18

Richard MacCutchan

else {
    TRACE(("TCP Data %d bytes received.\n"), TRecv_Size);
    ::ZeroMemory(&Cmd, sizeof(Cmd));
    memcpy(&Cmd, TRecvBuffer, TRecv_Size);
    return RESULT_SUCCESS;
}

Где Cmd определено в TCPClientRecv процесс, и достаточно ли он велик, чтобы содержать все скопированное с TRecvBuffer ?