1
votes

I am making a Matchmaking server for my custom Battleship game. I am a beginner at network coding, so I am sorry in advance for dumb questions. :P

Now closer to the topic. I use default Delphi Server/Client Socket component. I have my array declared in the public section (clients: array of TCustomWinSocket;), then on the main frame startup I set the length to zero (setLength(clients, 0);). Now the confusing part for me: whenever I try to access any element of array program throws an Access Violation exception. I have checked in any known way, program NEVER exceeds the length of the array.

Here is code example which throws exception:

procedure Tmain.Button1Click(Sender: TObject);
var
i: integer;
begin
  for i := 0 to length(clients) do begin
    if assigned(clients[i]) then begin
      showmessage(IntToStr(i));
      showmessage(IntToStr(i) + ': ' + clients[i].RemoteAddress);
    end;
  end;
end;

Another example:

procedure Tmain.serverClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  addLog('(' + Socket.RemoteAddress + ':' + IntToStr(Socket.RemotePort) + ') Клиент подключился');
  if length(clients) <> 0 then begin
    showmessage(IntToStr(length(clients)));
    setLength(clients, length(clients) + 1);
    showmessage(IntToStr(length(clients)));
    clients[length(clients)] := Socket;
  end
  else if length(clients) = 0 then begin
    showmessage(IntToStr(length(clients)));
    clients[0] := Socket;
  end;

end;

Basically, every time I use this array it gives an access violation. I can't get it, I limit the code to stay in the array length, but it does not. Or, perhaps, it is as usual my stupidity that caused it?

Any way, I could really use some help.

Thanks in advance! :)

1
Hello, @KenWhite ! Thanks for answer! When I was testing program before that was not the problem and the 0 element did exist, after it started throwing access violation I have not tried not using 0 index again, because I have used it in past, now when I tried you solution, it works again. I am so confused... But thanks again for the help!583746
See my answer below; you've got other problems with the code you posted as well.Ken White

1 Answers

4
votes

You're running off the end of the array in this loop. Length(clients) is one higher than the last index, because the index into a dynamic array starts at zero. You have to either use Length(clients) - 1 or High(clients) as the terminator of your loop.

procedure Tmain.Button1Click(Sender: TObject);
var
i: integer;
begin
  for i := 0 to High(clients) do begin // or Length(clients) - 1
    if assigned(clients[i]) then begin
      showmessage(IntToStr(i));
      showmessage(IntToStr(i) + ': ' + clients[i].RemoteAddress);
    end;
  end;
end;

You have a similar error in your second code block as well, plus another one that's pretty clear:

procedure Tmain.serverClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  addLog('(' + Socket.RemoteAddress + ':' + IntToStr(Socket.RemotePort) + ') Клиент подключился');
  if length(clients) <> 0 then begin
    showmessage(IntToStr(length(clients)));      // Need - 1 or High() here
    setLength(clients, length(clients) + 1);
    showmessage(IntToStr(length(clients)));      // Need - 1 or High() here
    clients[length(clients)] := Socket;
  end
  else if length(clients) = 0 then begin       // Second problem starts here
    showmessage(IntToStr(length(clients)));    // See text below
    clients[0] := Socket;                      
  end;                                         
end;

The second error is attempting to assign to clients[0] when Length(clients) = 0, because that's an invalid index. If the array length is zero, there is no element 0, because the array is empty - there are no elements in it - not a single one; you can't assign a value to an array that has zero elements in it.

The proper code for that entire block would be something like this - you don't need both tests, to test for length = 0, or to jump through all the hoops:

procedure Tmain.ServerClientConnect(Sender: TObject; Socket; TCustomSocket);
begin
  AddLog('Whatever you want to log.');
  SetLength(clients, Length(clients) + 1);
  Clients[High(Clients)] := Socket;
end;