¥送分给你150¥ 客户端或服务端程序结束了,还会不断地向对方发送重复的消息。

时间:2021-03-07 18:00:38

是阻塞方式的一个简单聊天程序。只能发送Edit里面的字符串。
用一个线程来控制其监听状态。

客户端或服务端程序结束了,只要对方没关,就还会不断地向对方发送重复的消息。

这是什么回事?

Up的人,有分
解决的人 另外再加100

22 个解决方案

#1


不懂,up

#2


up

#3


就是一方(Client.exe)退出程序后,竟然还能死循环的向另一方(Server.exe)
发送信息。这是怎么回事呢??

#4


呵呵~人家还没聊完你就关了,对你表示不满嘛~
不过不应该出现啊~估计不难,但是我没有这方面经验~

#5


是源源不断地发送消息,还是在退出之前在发送一次。建议看看socket的各个事件代码。

#6


是源源不断地发送消息

#7


而且我已经退出前把线程Teminel掉了阿。
会是什么原因阿?

#8


我方的程序都退出了,关闭了,还怎么向对方发送消息?不明白!

如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。

如果不能解决,请贴出代码,帮你想一下吧.

#9


客户端的代码:

unit Client;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls,WinSock;

type
  TSyncThread=class(TThread)
  protected
  procedure execute;override;
  private
  procedure RecvText;
  end;
type
  TMainFrame = class(TForm)
    EditServerIP: TEdit;
    EditServerPort: TEdit;
    LbPort: TLabel;
    LbIP: TLabel;
    BtnConnect: TButton;
    StatusBarClient: TStatusBar;
    ListBoxUsers: TListBox;
    ListBoxMsg: TListBox;
    LbMsg: TLabel;
    EditMsg: TEdit;
    BtnSend: TButton;
    BtnExit: TButton;
    procedure BtnExitClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BtnConnectClick(Sender: TObject);
    procedure BtnSendClick(Sender: TObject);
 
    procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
  private
   ThreadClient:TSyncThread;

    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrame: TMainFrame;
  ClientSocket:TSocket;
  BlockBuf:array [0..1024*4-1] of char;
  RecvBuf:array[0..1024*4-1] of char;
 const BufLength=1024*4;


implementation

{$R *.dfm}

procedure TSyncThread.execute;
begin
 while (true) do
 begin
  recv(ClientSocket,RecvBuf,BufLength,0);
  Synchronize(RecvText);
  MainFrame.Update;
 end;
end;

procedure TSyncThread.RecvText;
begin
 MainFrame.ListBoxUsers.Items.Add('Server');
 MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;

procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;

procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
  if WSAStartup($0101,aWSAData)<>0 then
   begin
   raise Exception.Create('Could not start up the Socket Dll');
   end;

end;

procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
  begin
    MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
  end;
  CloseSocket(ClientSocket);
end;

procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
 ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
  if ClientSocket=INVALID_SOCKET then
  begin
  StatusBarClient.SimpleText:='Can not Connect to a Server';
  exit;
  end;
 ca.sin_family:=PF_INET;
 ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
 hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
 if(hostaddr=-1) then
  begin
  statusBarClient.SimpleText:='The ip Addr is wrong ';
  exit;
  end
 else
  ca.sin_addr.S_addr:=hostaddr;
 if connect(ClientSocket,ca,sizeof(ca))<>0 then
   begin
   StatusBarClient.SimpleText:='Can not Connect to romete host';
   exit;
   end
 else
  begin
  StatusBarClient.SimpleText:='Connect to remote host succeed';
  ThreadClient:=TSyncThread.Create(false);
  BtnConnect.Enabled:=false;
  end;

end;

procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;

 

procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
 BtnSendClick(Sender);

end;

end.

#10


服务端的代码
unit Server;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls,Winsock;

type
  TSyncThread =class(TThread)
  protected
   procedure execute ; override;
  public
   procedure AddRecvMsg;
  end;
  TMainFrame = class(TForm)
    BtnStartServer: TButton;
    ListBoxUsers: TListBox;
    ListBoxMsg: TListBox;
    BtnExitServer: TButton;
    LbMsg: TLabel;
    EditMsg: TEdit;
    BtnSendMsg: TButton;
    StatusBarServer: TStatusBar;
    procedure BtnStartServerClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure BtnExitServerClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BtnSendMsgClick(Sender: TObject);    
    procedure EditMsgEnter(Sender: TObject);


  private
    { Private declarations }
    ThreadListen:TSyncThread;
  public
    { Public declarations }
  end;

var
  MainFrame: TMainFrame;
  ServerSocket :TSocket;
  RecvSocket :TSocket;
  BlockBuf:Array  [0..1024*4-1] of char;
  const BufLength =1024*4;
  
implementation

{$R *.dfm}
procedure TSyncThread.execute;
var
 ra:SOCKADDR_IN;
 ra_len:Integer;

begin
 ra_len:=sizeof(ra);
 RecvSocket:=accept(ServerSocket,@ra,@ra_len);
 while (true) do
  begin
  recv(RecvSocket,BlockBuf,BufLength,0);
  Synchronize(AddRecvMsg);
  MainFrame.Update;
  end;

  ;
end;
procedure TSyncThread.AddRecvMsg;

begin
          MainFrame.ListBoxUsers.Items.Add('Client');
          MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;

procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
 ca:SOCKADDR_IN;
begin
 ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
 if ServerSocket=INVALID_SOCKET then
 begin
  StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
  Exit;
 end
 else

    ca.sin_family:=PF_INET;
    ca.sin_port:=htons(3000);
    ca.sin_addr.S_addr:=INADDR_ANY;
    if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
    begin
    StatusBarServer.SimpleText:='Binding the Server Socket Error';
    CloseSocket(ServerSocket);
    exit;
    end
    else
     StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
     try
      listen(ServerSocket,5);
     except
      on e:Exception do
       showmessage(e.Message);
       end;
       BtnStartServer.Enabled:=false;
      ThreadListen:=TsyncThread.Create(false);



end;

procedure TMainFrame.FormCreate(Sender: TObject);
var
 aWSAData:TWSADATA;
begin
 if WSAStartup($0101,aWSAData)<>0 then
 raise Exception.Create('Can not load the Socket Dll#13');
 

end;

procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;

procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
  closesocket(ServerSocket);
if WSACleanup<>0 then
  MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);

end;

procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;



 

 

procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
    BtnSendMsgClick(Sender);
end;

end.

#11


帮忙看看谢谢

#12


分析你的代码,是不会出现那种情况的

打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。


#13


我也遇到过这个问题, 我是用andy组件时发现的。服务器端向客户端连续发送数据,客户端收到后就显示出来。后来我发现关了服务端后客户端仍然能显示数据。之后我在客户端检测与服务端的连接状态,当服务端关闭后,客户端能检测到,但仍然能从指定的端口读取数据。这个问题我还没解决,只当客户端检测到服务端已关闭时就不再去读取数据了。

#14


我理解如下:
  你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”

强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的

#15


是不是要在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室...

如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?

#16


HanJingJingHan(静) :谢谢你的分析,我才刚学delphi。可能你说得对
 服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
  closesocket(ServerSocket);
if WSACleanup<>0 then

如果这样还不能清除信息,那怎么做才对呢?谢谢

#17


我发现很有趣。打开一个server.exe.
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe

"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?

#18


试一下Delphi自带的两个组件,TSocoktServer/TSocoktClient,你所需要的绝大部分功能它都替你做好了,而它的功能也足够地强大,我公司的整个短信网关系统,后台处理系统都是用它做的,你可以读一下它的源码。另外如果你是用D5版本的话,它的Demo文件夹下有一个专门的文件夹我,有好多关于通信编程的源码,非常的实用。

#19


还有许多关于用Delphi进行网络编程的书籍上都有用Delphi写聊天室的源码和思想,注意事项。

如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...

#20


嗯,谢谢,可是这样不好阿,遇到问题解决不了,总是有点嘎达嘎大的感觉。。
哎。。

#21


如果是程序的某一个地方出问题,改动量小的话,就立马可以解决,问题是当一个问题头绪多乱或者不是三言两语能说清楚的话,就只能靠自己去学习了,旁人只能指个路。

相比之下,有个人指个方向,学习的进度就大不一样了。

#22


哎,那倒是,哦,你有油箱嘛?要不我发完整程序给你看看吧?谢谢。

#1


不懂,up

#2


up

#3


就是一方(Client.exe)退出程序后,竟然还能死循环的向另一方(Server.exe)
发送信息。这是怎么回事呢??

#4


呵呵~人家还没聊完你就关了,对你表示不满嘛~
不过不应该出现啊~估计不难,但是我没有这方面经验~

#5


是源源不断地发送消息,还是在退出之前在发送一次。建议看看socket的各个事件代码。

#6


是源源不断地发送消息

#7


而且我已经退出前把线程Teminel掉了阿。
会是什么原因阿?

#8


我方的程序都退出了,关闭了,还怎么向对方发送消息?不明白!

如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。

如果不能解决,请贴出代码,帮你想一下吧.

#9


客户端的代码:

unit Client;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls,WinSock;

type
  TSyncThread=class(TThread)
  protected
  procedure execute;override;
  private
  procedure RecvText;
  end;
type
  TMainFrame = class(TForm)
    EditServerIP: TEdit;
    EditServerPort: TEdit;
    LbPort: TLabel;
    LbIP: TLabel;
    BtnConnect: TButton;
    StatusBarClient: TStatusBar;
    ListBoxUsers: TListBox;
    ListBoxMsg: TListBox;
    LbMsg: TLabel;
    EditMsg: TEdit;
    BtnSend: TButton;
    BtnExit: TButton;
    procedure BtnExitClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BtnConnectClick(Sender: TObject);
    procedure BtnSendClick(Sender: TObject);
 
    procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
  private
   ThreadClient:TSyncThread;

    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrame: TMainFrame;
  ClientSocket:TSocket;
  BlockBuf:array [0..1024*4-1] of char;
  RecvBuf:array[0..1024*4-1] of char;
 const BufLength=1024*4;


implementation

{$R *.dfm}

procedure TSyncThread.execute;
begin
 while (true) do
 begin
  recv(ClientSocket,RecvBuf,BufLength,0);
  Synchronize(RecvText);
  MainFrame.Update;
 end;
end;

procedure TSyncThread.RecvText;
begin
 MainFrame.ListBoxUsers.Items.Add('Server');
 MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;

procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;

procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
  if WSAStartup($0101,aWSAData)<>0 then
   begin
   raise Exception.Create('Could not start up the Socket Dll');
   end;

end;

procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
  begin
    MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
  end;
  CloseSocket(ClientSocket);
end;

procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
 ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
  if ClientSocket=INVALID_SOCKET then
  begin
  StatusBarClient.SimpleText:='Can not Connect to a Server';
  exit;
  end;
 ca.sin_family:=PF_INET;
 ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
 hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
 if(hostaddr=-1) then
  begin
  statusBarClient.SimpleText:='The ip Addr is wrong ';
  exit;
  end
 else
  ca.sin_addr.S_addr:=hostaddr;
 if connect(ClientSocket,ca,sizeof(ca))<>0 then
   begin
   StatusBarClient.SimpleText:='Can not Connect to romete host';
   exit;
   end
 else
  begin
  StatusBarClient.SimpleText:='Connect to remote host succeed';
  ThreadClient:=TSyncThread.Create(false);
  BtnConnect.Enabled:=false;
  end;

end;

procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;

 

procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
 BtnSendClick(Sender);

end;

end.

#10


服务端的代码
unit Server;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls,Winsock;

type
  TSyncThread =class(TThread)
  protected
   procedure execute ; override;
  public
   procedure AddRecvMsg;
  end;
  TMainFrame = class(TForm)
    BtnStartServer: TButton;
    ListBoxUsers: TListBox;
    ListBoxMsg: TListBox;
    BtnExitServer: TButton;
    LbMsg: TLabel;
    EditMsg: TEdit;
    BtnSendMsg: TButton;
    StatusBarServer: TStatusBar;
    procedure BtnStartServerClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure BtnExitServerClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BtnSendMsgClick(Sender: TObject);    
    procedure EditMsgEnter(Sender: TObject);


  private
    { Private declarations }
    ThreadListen:TSyncThread;
  public
    { Public declarations }
  end;

var
  MainFrame: TMainFrame;
  ServerSocket :TSocket;
  RecvSocket :TSocket;
  BlockBuf:Array  [0..1024*4-1] of char;
  const BufLength =1024*4;
  
implementation

{$R *.dfm}
procedure TSyncThread.execute;
var
 ra:SOCKADDR_IN;
 ra_len:Integer;

begin
 ra_len:=sizeof(ra);
 RecvSocket:=accept(ServerSocket,@ra,@ra_len);
 while (true) do
  begin
  recv(RecvSocket,BlockBuf,BufLength,0);
  Synchronize(AddRecvMsg);
  MainFrame.Update;
  end;

  ;
end;
procedure TSyncThread.AddRecvMsg;

begin
          MainFrame.ListBoxUsers.Items.Add('Client');
          MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;

procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
 ca:SOCKADDR_IN;
begin
 ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
 if ServerSocket=INVALID_SOCKET then
 begin
  StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
  Exit;
 end
 else

    ca.sin_family:=PF_INET;
    ca.sin_port:=htons(3000);
    ca.sin_addr.S_addr:=INADDR_ANY;
    if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
    begin
    StatusBarServer.SimpleText:='Binding the Server Socket Error';
    CloseSocket(ServerSocket);
    exit;
    end
    else
     StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
     try
      listen(ServerSocket,5);
     except
      on e:Exception do
       showmessage(e.Message);
       end;
       BtnStartServer.Enabled:=false;
      ThreadListen:=TsyncThread.Create(false);



end;

procedure TMainFrame.FormCreate(Sender: TObject);
var
 aWSAData:TWSADATA;
begin
 if WSAStartup($0101,aWSAData)<>0 then
 raise Exception.Create('Can not load the Socket Dll#13');
 

end;

procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;

procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
  closesocket(ServerSocket);
if WSACleanup<>0 then
  MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);

end;

procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;



 

 

procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
    BtnSendMsgClick(Sender);
end;

end.

#11


帮忙看看谢谢

#12


分析你的代码,是不会出现那种情况的

打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。


#13


我也遇到过这个问题, 我是用andy组件时发现的。服务器端向客户端连续发送数据,客户端收到后就显示出来。后来我发现关了服务端后客户端仍然能显示数据。之后我在客户端检测与服务端的连接状态,当服务端关闭后,客户端能检测到,但仍然能从指定的端口读取数据。这个问题我还没解决,只当客户端检测到服务端已关闭时就不再去读取数据了。

#14


我理解如下:
  你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”

强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的

#15


是不是要在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室...

如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?

#16


HanJingJingHan(静) :谢谢你的分析,我才刚学delphi。可能你说得对
 服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
  closesocket(ServerSocket);
if WSACleanup<>0 then

如果这样还不能清除信息,那怎么做才对呢?谢谢

#17


我发现很有趣。打开一个server.exe.
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe

"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?

#18


试一下Delphi自带的两个组件,TSocoktServer/TSocoktClient,你所需要的绝大部分功能它都替你做好了,而它的功能也足够地强大,我公司的整个短信网关系统,后台处理系统都是用它做的,你可以读一下它的源码。另外如果你是用D5版本的话,它的Demo文件夹下有一个专门的文件夹我,有好多关于通信编程的源码,非常的实用。

#19


还有许多关于用Delphi进行网络编程的书籍上都有用Delphi写聊天室的源码和思想,注意事项。

如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...

#20


嗯,谢谢,可是这样不好阿,遇到问题解决不了,总是有点嘎达嘎大的感觉。。
哎。。

#21


如果是程序的某一个地方出问题,改动量小的话,就立马可以解决,问题是当一个问题头绪多乱或者不是三言两语能说清楚的话,就只能靠自己去学习了,旁人只能指个路。

相比之下,有个人指个方向,学习的进度就大不一样了。

#22


哎,那倒是,哦,你有油箱嘛?要不我发完整程序给你看看吧?谢谢。