Q&A

  • 소켓 사용 시 Sendstream후 free하려고 하면 에러가 발생하는 이유는?
// 이전에 했던 무식한 반복루프에 의한 것이 아닌

// 메시지 패킷으로 주고 받기를 시도합니다....

// SendData라 평션에서 메모리 스트림을 생성하지만

// 파괴시키지는 않았습니다.

// 이유는 sendStream후 free할려고 하면 에러가 자꾸 발생해서

// 그냥 나둬 버렸습니다....

// 고수님들의 고견 기다립니다....

unit uXSocket;



interface



uses

windows, messages, sysutils, classes, scktcomp, Dialogs, stdctrls, controls;



const

mtText = $FF00000000000000; // 텍스트

ctText = 'FF00000000000000';



mtData = $FF00000000000001; // 데이타

ctData = 'FF00000000000001';



mtDataEnd = $FF00000000000002; // 데이타 종료시...

ctDataEnd = 'FF00000000000002';



mtTransNM = $FF00000000000003; // 전송시파일명

ctTransNM = 'FF00000000000003'; // 전송시파일명



mtACK0 = $FF00000000000004; // 전송할 수 있는 상태

ctACK0 = 'FF00000000000004'; //



mtACK1 = $FF00000000000005; // 전송시 응답여부1

ctACK1 = 'FF00000000000005'; //



mtACK2 = $FF00000000000006; // 전송시 응답여부2

ctACK2 = 'FF00000000000006'; //



mtFILE = $FF00000000000007; // 파일보내도 되겄냐...

ctFILE = 'FF00000000000007'; //



mtLens = 1024;



type

Pekit = record

msgtp : String[16];

postion : Integer;

buffsize: integer;

dat: array[0..mtLens-1] of char;

end;



Function FrontToBack(vValue: String): String;

Function RPos(Const vSubStr: String; Const vValue: String): Integer;

Function GetMemoLine(memo:TCustomMemo): Integer;

Function GetMemoCol(memo:TCustomMemo): Integer;

Function Memo2Str(sList: TCustomMemo; itemi: Integer): String;

Procedure AddStr(var Vvalue: String; vStr:Array of String);

Function Strings2Str(sList: TStrings; itemi: Integer): String;

function Int2Hex(nFmt: Integer): String;

Function Int642Hex(nFmt: Int64): String;



//=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-

// 소켓관련 파일 송수신 루틴 및 텍스트 자료 전송....

//=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-

Function SendData(clSocket: TCustomWinSocket; theData: String; nFmt: int64=mtText): Boolean; overload;

Function SendData(clSocket: TCustomWinSocket; theData: pChar; nFmt: int64): Integer; overload;

Procedure SendString(clSocket: TCustomWinSocket; theData: String; nFmt: int64);

Procedure SocketReceive(clSocket: TCustomWinSocket; ssdata : Pekit);

Procedure SocketSend(clSocket: TCustomWinSocket; ssdata : Pekit; sPathFile: String);



var

defaultDownFolder: String;

DownLoadFile: Integer;

old_pekit: pekit;



implementation



Function FrontToBack(vValue: String): String;

var

iz, mLen: Integer;

Begin

mLen := Length(vValue);

SetLength(Result, mLen);

For iz := mLen downto 1 do Result[iz] := vValue[mLen+1-iz];

End;



Function RPos(Const vSubStr: String; Const vValue: String): Integer;

Begin

Result := pos(vSubStr, FrontToBack(vValue));

if Result > 0 Then Result := Length(vValue)+1-Result;

End;



Function GetMemoLine(memo:TCustomMemo): Integer;

var

LineNum:LongInt;

begin

LineNum:=SendMessage(Memo.Handle, EM_LINEFROMCHAR, Memo.SelStart, 0);

Result := LineNum+1;

end;



Function GetMemoCol(memo:TCustomMemo): Integer;

var

LineNum, CharseBeforeLine:LongInt;

begin

LineNum:=SendMessage(Memo.Handle, EM_LINEFROMCHAR, Memo.SelStart, 0);

CharseBeforeLine := SendMessage(Memo.Handle, EM_LINEINDEX, LineNum, 0);

Result := Memo.SelStart - CharseBeforeLine + 1;

end;





Function Int2Hex(nFmt: Integer): String;

var

z: Integer;

u, uh, ul: Byte;

Begin

result := '';

for z := 3 downto 0 do Begin

u := (nFmt shr (z * 8)) and $FF;

uh := (u shr 4) and $F;

ul := u and $F;

if uh >= 10 Then result := Result + Chr(Byte('A')+uh-10)

else result := Result + Chr(Byte('0')+uh);

if ul >= 10 Then result := Result + Chr(Byte('A')+ul-10)

else result := Result + Chr(Byte('0')+ul);

End;

End;



Function Int642Hex(nFmt: Int64): String;

var

z: Integer;

u, uh, ul: Byte;

Begin

result := '';

for z := 7 downto 0 do Begin

u := (nFmt shr (z * 8)) and $FF;

uh := (u shr 4) and $F;

ul := u and $F;

if uh >= 10 Then result := Result + Chr(Byte('A')+uh-10)

else result := Result + Chr(Byte('0')+uh);

if ul >= 10 Then result := Result + Chr(Byte('A')+ul-10)

else result := Result + Chr(Byte('0')+ul);

End;

End;



Procedure AddStr(var Vvalue: String; vStr:Array of String);

var

i : Integer;

Begin

For i := Low(vStr) to High(vStr) do Vvalue := VValue + vStr[i];

End;



Function Strings2Str(sList: TStrings; itemi: Integer): String;

var

iz: Integer;

Begin

for iz := itemi to sList.Count-1 do AddStr(Result, [sList.Strings[iz]]);

End;



Function Memo2Str(sList: TCustomMemo; itemi: Integer): String;

var

iz, iu: Integer;

Begin

iu := 0;

if itemi < 0 Then iu := GetMemoLine(sList)

else if itemi >= 0 Then iu := itemi;

for iz := iu to sList.Lines.Count-1 do AddStr(Result, [sList.Lines.Strings[iz]]);

End;



Function SendData(clSocket: TCustomWinSocket; theData: String; nFmt: int64): Boolean;

var

lvs : TMemoryStream;

p : Pekit;

Begin

lvs := TMemoryStream.Create;

Zeromemory(@p,sizeof(pekit));

p.msgtp := int642Hex(nFmt);

p.buffsize := Length(theData);

strpcopy(@p.dat, theData);

lvs.Write(p, sizeof(p));

lvs.Position := 0;

Result := clSocket.Sendstream(lvs);

// 작업이 끝나면 자동으로 Free되는 것 같음....

// 그래서 Free를 안했는데 Free하면 에러발생

// 이루틴으로 인하여 전송중에 에러 발생....

end;



Function SendData(clSocket: TCustomWinSocket; theData: PChar; nFmt: int64): Integer;

var

p : Pekit;

Begin

Zeromemory(@p,sizeof(pekit));

p.msgtp := int642Hex(nFmt);

p.buffsize := StrLen(theData);

strpcopy(p.dat, theData);

Result := clSocket.SendBuf(p, sizeof(Pekit));

end;



Procedure SendString(clSocket: TCustomWinSocket; theData: String; nFmt: int64);

var

px : String;

Begin

px := int642Hex(nFmt) + theData;

clSocket.SendText(px)

end;



////////////////////////////////////////////////////////////////////////////////

// 파일을 받는 쪽에서 보내는 쪽으로의 메세지 송출

Procedure SocketReceive(clSocket: TCustomWinSocket; ssdata : Pekit);

var

pathandFile: String;

Begin

// 파일보낸다라고 보냈을때 그럼 보내라는 패킷을 날린다....

if ssdata.msgtp = ctFILE Then Begin

SendData(clSocket, ssdata.dat, mtACK0);

Exit;

End;

// 파일명을 보냈다라고 했을때 조치후 잘받았다라는 패킷을 날린다....

if ssdata.msgtp = ctTransNM Then Begin

pathandFile := (*defaultDownFolder +*) strpas(ssdata.dat);

DownLoadFile := FileCreate(pathandFile);

if DownLoadFile = -1 Then Exit;

FileSeek(DownLoadFile, 0, 0);

SendData(clSocket, ssdata.dat, mtACK1);

end

else if ssdata.msgtp = ctData Then Begin // 데이타를 보냈으니 조치후 잘받았다를 보낸다....

if DownLoadFile = -1 Then Exit;

FileWrite(DownLoadFile, ssdata.dat, ssdata.buffsize);

SendData(clSocket, ssdata.dat, mtACK1);

End

else if ssdata.msgtp = ctDataEnd Then Begin // 데이타의 마지막부분을 받았을 경우는 조치후

if DownLoadFile = -1 Then Exit; // 파일송수신은 끝이다라 메시지를 보낸다....

FileWrite(DownLoadFile, ssdata.dat, ssdata.buffsize);

FileClose(DownLoadFile);

SendData(clSocket, ssdata.dat, mtACK2);

End;

End;



////////////////////////////////////////////////////////////////////////////////

// 파일보내는 쪽에서 받는 쪽으로의 송출

Procedure SocketSend(clSocket: TCustomWinSocket; ssdata : Pekit; sPathFile: String);

var

nread: Integer;

Begin

// 파일명을 보내라는 메세지가 날라왔을때.....

// 파일명을 보낸다....

if ssdata.msgtp = ctACK0 Then Begin // 파일 받기 준비완료...

DownLoadFile := FileOpen(sPathFile, fmOpenread or fmShareDenyNone);

if DownLoadFile = -1 Then Exit;

FileSeek(DownLoadFile, 0, 0);

SendData(clSocket, sPathFile, mtTransNM);

End else if ssdata.msgtp = ctACK1 Then Begin // 파일명을 받아서 초기확 완료되었으니 데이타좀 보내줘라는

if DownLoadFile = -1 Then Exit; // 메시지가 왔을때 데이터를 보낸다....

nread := FileRead(DownLoadFile, ssdata.dat, sizeof(ssdata.dat));

if nread < mtLens Then SendData(clSocket, @ssdata.dat, mtDataEnd)

else SendData(clSocket, @ssdata.dat, mtData);

end else if ssdata.msgtp = ctACK2 Then Begin // 데이타를 다받았으니 종료해도 되라는 메시지를 받았을때....

if DownLoadFile = -1 Then Exit;

FileClose(DownLoadFile);

End;

//ZeroMemory(@old_pekit, sizeof(pekit));

//old_pekit.msgtp := ssdata.msgtp;

//old_pekit.buffsize := ssdata.buffsize;

End;



initialization

defaultDownFolder := 'C:';

finalization

end.





// 질문입니다요....

// 파일 전송에 관련된 API를 이 싸이트의 여러질문과 답변을 근거로

// 한번 만들어봤습니다요...

// 파일 송수신을 하기 위해서 F12키를 누르면

// 그때부터 패킷에 의한 동작을 수행하는데 수행중 메모리 오류가 발생합니다...

// 관련하여 소스를 첨언드립니다....

// 단축키 부분

// 아래에 계속 이어집니다.....

procedure TChatForm.Memo1KeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

begin

if Key = VK_F11 Then begin

if IsServer Then

SendData(ServerSocket.Socket.Connections[0], Strings2Str(Memo1.Lines, -1))

else

SendData(ClientSocket.Socket, Strings2Str(Memo1.Lines, -1));

end

else if Key = VK_F12 Then Begin

if IsServer Then begin

Senddata(ServerSocket.Socket.Connections[0], 'c:cismainmenu.exe', mtFile);

End

else Begin

Senddata(ClientSocket.Socket, 'c:cismainmenu.exe', mtFile);

End;

End;

end;



// 메시지를 받는 부분의 이벤트 동작

procedure TChatForm.ClientSocketRead(Sender: TObject;

Socket: TCustomWinSocket);

var

ssdata:Pekit;

begin

socket.ReceiveBuf(ssdata, sizeof(ssdata));

if ssdata.msgtp = ctText Then Begin

Memo2.Lines.Add(strpas(ssdata.dat));

End

else if (ssdata.msgtp = ctData) or (ssdata.msgtp = ctDataEnd)

or (ssdata.msgtp = ctTransNm) Then Begin

SocketReceive(Socket, ssdata);

End

else if (ssdata.msgtp = ctACK0) or (ssdata.msgtp = ctACK1)

or (ssdata.msgtp = ctACK2) Then Begin

socketSend(Socket, ssdata, 'c:cismainmenu.exe');

end;

end;



// 메시지를 받는 부분의 이벤트 동작

procedure TChatForm.ServerSocketClientRead(Sender: TObject;

Socket: TCustomWinSocket);

var

ssdata:Pekit;

begin

socket.ReceiveBuf(ssdata, sizeof(ssdata));

if ssdata.msgtp = ctText Then Begin

Memo2.Lines.Add(strpas(ssdata.dat));

End

else if (ssdata.msgtp = ctFILE) or (ssdata.msgtp = ctData) or (ssdata.msgtp = ctDataEnd)

or (ssdata.msgtp = ctTransNm) Then Begin

SocketReceive(Socket, ssdata);

End

else if (ssdata.msgtp = ctACK0) or (ssdata.msgtp = ctACK1)

or (ssdata.msgtp = ctACK2) Then Begin

socketSend(Socket, ssdata, 'c:cismainmenu.exe');

end;

end;





0  COMMENTS