分享
 
 
 

用C++ Builder中的TServerSocket,TClientSocket来写网络通讯程序

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

本文主要介绍如何在C++ Builder中用TServerSocket,TClientSocket来写一个网络间短包,文件传输的程序,这个程序可以支持:1.局域网上的传输。2.局域网与公网的传输(双向传输),在第二篇文章中我将用socket api写一个客户端和服务器,功能和本文中的功能一样。使用通讯协议TCP,这里的客户端和服务器使用的都是阻塞模式---多线程。

Client:

.h File

class ClientThread : public TThread

{

private:

AnsiString File;

TClientSocket* ClientSocket;

TWinSocketStream* WskStream;

protected:

void __fastcall Execute();

public:

__fastcall ClientThread(AnsiString IPAddr,

WORD Port, AnsiString file);

};

.cpp File

void __fastcall ClientThread::Execute()

{

//Send Text or SendFile

UINT TimeOut=60000;

char buf[4096];

//char IPAddress[32];

//GetIPAddress(IPAddress);//IPAddress

WskStream = new TWinSocketStream(ClientSocket->Socket, TimeOut);

if(Form1->CheckBox1->Checked)//Determine whether to send short package or send file.

{

String S=Form1->TxtEdit->Text;

int TxtLen=Form1->TxtEdit->Text.Length();

strncpy(buf,S.c_str(),TxtLen);

ClientSocket->Active=true;

WskStream->Write("TEXT\0",5);//Send Text Flag

WskStream->Write(IPAddress,32);//Send IP Address

WskStream->Write(buf,TxtLen);//Send Text String

WskStream->Write(buf,TxtLen);

if(WskStream->WaitForData(TimeOut))

{

buf[0]='\0';

FlagBuf[0]='\0';

IPAddress[0]='\0';

WskStream->Read(FlagBuf,5);

WskStream->Read(IPAddress,32);

int nSize=0;

nSize=WskStream->Read(buf,TxtLen);

buf[nSize]='\0';

if(!StrPas(buf).IsEmpty())

{

SaveLog("Received a text!");

SaveLog("Client:"+StrPas(IPAddress)+"\r\nStart Time:"+DateTimeToStr(Now()));

SaveLog("Text Content:"+StrPas(buf));

FLASHWINFO FSHINFO;

::ZeroMemory(&FSHINFO,sizeof(FLASHWINFO));

FSHINFO.cbSize=sizeof(FLASHWINFO);

FSHINFO.hwnd=Application->Handle;

FSHINFO.dwFlags=FLASHW_TRAY|FLASHW_CAPTION;

FSHINFO.uCount=10;

FSHINFO.dwTimeout=200;

::FlashWindowEx(&FSHINFO);

Form1->RecEdit->Lines->Add("Received Length:"+String(nSize));

Form1->RecEdit->Lines->Add("Received:"+StrPas(buf));

//SaveLog("Client:"+StrPas(IPAddress)+"\r\nEnd Time:"+DateTimeToStr(Now()));

}

}

}

else

{

int nLen;

int hFile;

int nSize;

char Path[255];//Path Buffer

char FileName[255];//FileName Buffer;

char FileExt[5];//Extension Buffer

char FlagBuf[5];

static int num=0;

AnsiString sFileName=ExtractFileName(File);

for(int k=sFileName.Length();k>0;k--)

{

if(sFileName.SubString(k,1)==".")

{

sFileName=sFileName.SubString(1,k-1);

break;

}

}

AnsiString sPath=ExtractFilePath(File);

AnsiString sExtension=ExtractFileExt(File);

strcpy(FileName,sFileName.c_str());//FileName

strcpy(Path,sPath.c_str()); //Path

strcpy(FileExt,sExtension.c_str()); ://Extension

try {

hFile = -1;

ClientSocket->Active = true;

hFile = FileOpen(File, fmOpenRead);

if (hFile != -1) {

nSize = GetFileSize((HANDLE)

hFile, NULL);

//Send the Flag

WskStream->Write("FILE\0",5);

//Send the name of directory

WskStream->Write(Path,255);

//Send the filename

WskStream->Write(FileName,255);

//Send the extension of file

WskStream->Write(FileExt,5);

//Send client's IP addresss

WskStream->Write(IPAddress,32);

//Send the length

WskStream->Write(&nSize, 4);

//Send the data

for(; nSize>0; nSize-=nLen) {

nLen = min((int)sizeof(

buf), nSize);

nLen = FileRead(hFile, buf,

nLen);

if (nLen<=0) break;

WskStream->Write(buf, nLen);

}

}

FileClose(hFile);//Send Completely

//Client is beginning to read data

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(FlagBuf,5);

}

if(WskStream->WaitForData(TimeOut))//Obtain the directory's name

{

WskStream->Read(Path,255);

}

//If the directory obtained from client doesnot exist,the create it

if(!DirectoryExists(StrPas(Path)))

{

CreateDir(StrPas(Path));

}

//Obtain the FileName

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(FileName,255);

}

//Obtain the extension

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(FileExt,5);

}

//Obtain the client's IPAddress

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(IPAddress,32);

}

AnsiString S=StrPas(Path)+StrPas(FileName)+StrPas(FileExt);

buf[0]='\0';

strcpy(buf,S.c_str());

while(1) {

if (FileExists(buf)) {

S=StrPas(Path)+StrPas(FileName)+"%03d"+StrPas(FileExt);

wsprintf(buf, S.c_str(),

num);

num++;

//Created Susscessfully

} else break;

}

hFile = FileCreate(buf);

if (hFile==-1)

{

Application->MessageBox("Failed to create file!","Error",MB_OK+MB_ICONERROR);

ClientSocket->Active=false;

delete WskStream;

Terminate();

return;

}

SaveLog("Received a file:"+StrPas(buf));

SaveLog("Client:"+StrPas(IPAddress)+"\r\nStart Time:"+DateTimeToStr(Now()));

try {

DWORD dwTick = GetTickCount();

//Obtain the length

if (WskStream->WaitForData(

TimeOut)) {

nLen = WskStream->Read(

&nSize, 4);

if (nLen!=4) nSize = 0;

}

else

nSize = 0;

//Reading data

for(; nSize>0 && !Terminated;

nSize-=nLen) {

if (!WskStream->WaitForData(

5000)) {

if (GetTickCount()-dwTick

<TimeOut)

continue;

::MessageBox(NULL,"Timeout,the thread has been terminated!","Error",MB_OK|MB_ICONERROR);

ClientSocket->Active=false;

break;

}

nLen = WskStream->Read(buf,

sizeof(buf));

dwTick = GetTickCount();

if (nLen <= 0) {

//Read Error

ClientSocket->Active=false;

::MessageBox(NULL,"Read Error,the thread has been terminated!","Error",MB_OK|MB_ICONERROR);

break;

}

//Combine the data

FileWrite(hFile, buf, nLen);

}

Form1->RecEdit->Lines->Add("You got a file from server,which was saved in "+StrPas(Path));

SaveLog("Client:"+StrPas(IPAddress)+"\r\nEnd Time:"+DateTimeToStr(Now()));

FLASHWINFO FSHINFO;

::ZeroMemory(&FSHINFO,sizeof(FLASHWINFO));

FSHINFO.cbSize=sizeof(FLASHWINFO);

FSHINFO.hwnd=Application->Handle;

FSHINFO.dwFlags=FLASHW_TRAY|FLASHW_CAPTION;

FSHINFO.uCount=10;

FSHINFO.dwTimeout=200;

::FlashWindowEx(&FSHINFO);

FileClose(hFile);

}

catch(Exception& e) {

ClientSocket->Active=false;

MessageBox(0, e.Message.c_str(),

"Error", MB_ICONERROR);

}

}

catch(Exception& e) {

ClientSocket->Active=false;

::MessageBox(0, e.Message.c_str(),

"Error", MB_OK|MB_ICONERROR);

}

FileClose(hFile);

}

delete WskStream; // delete ClientSocket;

}

//Begin to send package

void __fastcall TForm1::Button1Click(TObject *Sender)

{

int Port;

AnsiString Addr;

Addr = IPAddr->Text.Trim();

if (Addr.IsEmpty()) {

IPAddr->SetFocus();

Application->MessageBox("Please enter the client's address!","Warning",MB_OK|MB_ICONWARNING);

return;

}

try {

Port = ClientPort->Text.ToInt();

}

catch(Exception& e) {

ShowMessage(e.Message);

ClientPort->SetFocus(); return;

}

if(CheckBox1->Checked) //Send Text

{

if(TxtEdit->Text.IsEmpty())

{

::MessageBox(0,"Please enter the text string which you want to send!","Error",MB_OK+MB_ICONERROR);

return;

}

new ClientThread(Addr,Port,"");

}

else //Send File

{

if (OpenDialog1->Execute())

new ClientThread(Addr, Port,

OpenDialog1->FileName); //Begin to send data

}

}

Server:

.h File

//My Comments:

//At design-time,please place a TServerSocket Component on your form and set its clientype to stThreadBlocking.

//Server Thread Class

//The Server Can not only receives the packages coming from Clients,but also deliver the package to the clients after

processing upon the package.

class SrvThread : public TServerClientThread

{

private:

UINT FTimeOut;

TWinSocketStream* WskStream;

TThread *pThread;

protected:

void __fastcall ClientExecute();

public:

__fastcall SrvThread(TServerClientWinSocket*);

__property UINT TimeOut = { read=FTimeOut, write=FTimeOut };

};

void __fastcall SrvThread::ClientExecute()

{

TimeOut = 60000; file://60 Seconds

WskStream = new TWinSocketStream(ClientSocket, TimeOut);

file://Send Text or File

char FlagBuf[5];

char buf[4096];

char IPAddress[32];

SMS[0]='\0';

RecIPAddr[0]='\0';

if(WskStream->WaitForData(TimeOut)) file://Obtain Flag:File or Text

{

WskStream->Read(FlagBuf,5);

}

file://Save the flag received from clients

strcpy(Flag,FlagBuf);

if(StrPas(FlagBuf)=="TEXT")

{

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(IPAddress,32);

}

file://Save the client's IPAddress

strcpy(RecIPAddr,IPAddress);

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(buf,4096);

}

file://Save the short message received from clients

strcpy(SMS,buf);

SaveLog("Received a text!");

SaveLog("Client:"+StrPas(IPAddress)+"\r\nStart Time:"+DateTimeToStr(Now()));

SaveLog("Text Content:"+StrPas(SMS));

SaveLog("Client:"+StrPas(IPAddress)+"\r\nEnd Time:"+DateTimeToStr(Now()));

Form1->Memo1->Lines->Add("Text Content:"+StrPas(buf));

FLASHWINFO FSHINFO;

::ZeroMemory(&FSHINFO,sizeof(FLASHWINFO));

FSHINFO.cbSize=sizeof(FLASHWINFO);

FSHINFO.hwnd=Application->Handle;

FSHINFO.dwFlags=FLASHW_TRAY|FLASHW_CAPTION;

FSHINFO.uCount=10;

FSHINFO.dwTimeout=200;

::FlashWindowEx(&FSHINFO);

if(Form1->adv->Checked)//Automatically Deliver To Client

{

if(StrPas(Flag).IsEmpty() || StrPas(RecIPAddr).IsEmpty() || StrPas(SMS).IsEmpty())

{

Application->MessageBox("You can't deliver because no data are received!","Error",MB_OK+MB_ICONERROR);

return;

}

WskStream->Write(FlagBuf,5);

WskStream->Write(Form1->ComboBox1->Text.c_str(),32);

WskStream->Write(SMS,4096);

::Sleep(500);//Delay for 500ms

ClientSocket->Close();

}

if(Form1->spt->Checked)//Automatically deliver to serial port on local computer

{

StrCat(SMS,FlagBuf);

StrCat(SMS,Form1->ComboBox1->Text.c_str());

// SaveLog("Write Serial Port "+Form1->Port);

// SaveLog("Start Time:"+DateTimeToStr(Now()));

// SaveLog("End Time:"+DateTimeToStr(Now()));

pThread=new TWriteCommThread(Form1->Port,Form1->BaudRate,(void*)buf,1000);

pThread->Terminate();

}

}

else

{

if(StrPas(FlagBuf).Pos("GET")) file://GPRS

{

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(buf,4096);

}

file://Save the flag to Flag

strcpy(Flag,"GPRS");

file://Save the frame to SMS

strcpy(SMS,buf);

file://Set the destination IP

strcpy(RecIPAddr,"127.0.0.1");

SaveLog("Received a package from GPRS");

SaveLog("Start Time:"+DateTimeToStr(Now()));

SaveLog(StrPas(FlagBuf)+StrPas(buf));

SaveLog("End Time:"+DateTimeToStr(Now()));

Form1->Memo1->Lines->Add(StrPas(FlagBuf)+StrPas(buf));

FLASHWINFO FSHINFO;

::ZeroMemory(&FSHINFO,sizeof(FLASHWINFO));

FSHINFO.cbSize=sizeof(FLASHWINFO);

FSHINFO.hwnd=Application->Handle;

FSHINFO.dwFlags=FLASHW_TRAY|FLASHW_CAPTION;

FSHINFO.uCount=10;

FSHINFO.dwTimeout=200;

::FlashWindowEx(&FSHINFO);

if(Form1->adv->Checked)

{

if(StrPas(Flag).IsEmpty() || StrPas(RecIPAddr).IsEmpty() || StrPas(SMS).IsEmpty())

{

Application->MessageBox("You can't deliver because no data are received!","Error",MB_OK+MB_ICONERROR);

return;

}

WskStream->Write(FlagBuf,5);

WskStream->Write(Form1->ComboBox1->Text.c_str(),32);

WskStream->Write(SMS,4096);

::Sleep(500);//ms

ClientSocket->Close();

}

if(Form1->spt->Checked) file://Automatically deliver to serial port on local computer

{

StrCat(SMS,FlagBuf);

StrCat(SMS,Form1->ComboBox1->Text.c_str());

file://SaveLog("Write Serial Port "+Form1->Port);

file://SaveLog("Start Time:"+DateTimeToStr(Now()));

file://SaveLog("End Time:"+DateTimeToStr(Now()));

pThread=new TWriteCommThread(Form1->Port,Form1->BaudRate,(void*)SMS,4096);

pThread->Terminate();

}

}

else

{

int nLen;

int nSize;

int hFile;

char Path[255]; file://Path

char FileName[255]; file://FileName

char FileExt[5]; file://Extension

static int num=0;

file://Obtain the directory's name

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(Path,255);

}

file://If the directory obtained from client doesnot exist,the create it

if(!DirectoryExists(StrPas(Path)))

{

CreateDir(StrPas(Path));

}

file://Obtain the FileName

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(FileName,255);

}

file://Obtain the extension

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(FileExt,5);

}

file://Obtain the client's IPAddress

if(WskStream->WaitForData(TimeOut))

{

WskStream->Read(IPAddress,32);

}

file://Save the client's IPAddress

strcpy(RecIPAddr,IPAddress);

AnsiString S=StrPas(Path)+StrPas(FileName)+StrPas(FileExt);

strcpy(buf,S.c_str());

while(1) {

if (FileExists(buf)) {

S=StrPas(Path)+StrPas(FileName)+"%03d"+StrPas(FileExt);

wsprintf(buf, S.c_str(),

num);

num++;

file://Created Susscessfully

} else break;

}

hFile = FileCreate(buf);

if (hFile==-1)

{

Application->MessageBox("Failed to create file on server!","Error",MB_OK+MB_ICONERROR);

delete WskStream;

Terminate();

return;

}

file://Save the filename received from clients

strncpy(RecFile,buf,255);

SaveLog("Received a file:"+StrPas(buf));

SaveLog("Client:"+StrPas(IPAddress)+"\r\nStart Time:"+DateTimeToStr(Now()));

try {

DWORD dwTick = GetTickCount();

file://Obtain the length

if (WskStream->WaitForData(

TimeOut)) {

nLen = WskStream->Read(

&nSize, 4);

if (nLen!=4) nSize = 0;

}

else

nSize = 0;

file://Reading data

for(; nSize>0 && !Terminated;

nSize-=nLen) {

if (!WskStream->WaitForData(

5000)) {

if (GetTickCount()-dwTick

<TimeOut)

continue;

::MessageBox(NULL,"Timeout,the thread has been terminated!","Error",MB_OK|MB_ICONERROR);

break;

}

nLen = WskStream->Read(buf,

sizeof(buf));

dwTick = GetTickCount();

if (nLen <= 0) {

file://Read Error

::MessageBox(NULL,"Read Error,the thread has been terminated!","Error",MB_OK|MB_ICONERROR);

break;

}

file://Combine the data

FileWrite(hFile, buf, nLen);

}

SaveLog("Client:"+StrPas(IPAddress)+"\r\nEnd Time:"+DateTimeToStr(Now()));

Form1->Memo1->Lines->Add("You got a file received from client,which was saved in "+StrPas(Path));

file://Application->MessageBox("Server has successfully received the data !","Notification",MB_OK+MB_ICONINFORMATION);

FLASHWINFO FSHINFO;

::ZeroMemory(&FSHINFO,sizeof(FLASHWINFO));

FSHINFO.cbSize=sizeof(FLASHWINFO);

FSHINFO.hwnd=Application->Handle;

FSHINFO.dwFlags=FLASHW_TRAY|FLASHW_CAPTION;

FSHINFO.uCount=10;

FSHINFO.dwTimeout=200;

::FlashWindowEx(&FSHINFO);

FileClose(hFile);//Read Completely

if(Form1->adv->Checked)//Automatically Deliver

{

if(StrPas(Flag).IsEmpty() || StrPas(RecIPAddr).IsEmpty())

{

Application->MessageBox("You can't deliver because no data are received!","Error",MB_OK+MB_ICONERROR);

return;

}

file://Send Data

try

{

buf[0]='\0';

hFile = -1;

hFile = FileOpen(StrPas(RecFile), fmOpenRead);

if (hFile != -1) {

nSize = GetFileSize((HANDLE)

hFile, NULL);

file://Send the Flag

WskStream->Write("FILE\0",5);

file://Send the name of directory

WskStream->Write(Path,255);

file://Send the filename

WskStream->Write(FileName,255);

file://Send the extension of file

WskStream->Write(FileExt,5);

file://Send client's IP addresss

WskStream->Write(Form1->ComboBox1->Text.c_str(),32);

file://Send the length

WskStream->Write(&nSize, 4);

file://Send the data

for(; nSize>0; nSize-=nLen) {

nLen = min((int)sizeof(

buf), nSize);

nLen = FileRead(hFile, buf,

nLen);

if (nLen<=0) break;

WskStream->Write(buf, nLen);

}

}

} //try

catch(Exception& e) {

ClientSocket->Close();

::MessageBox(0, e.Message.c_str(),

"Error", MB_OK|MB_ICONERROR);

}

FileClose(hFile);

}//if

}//catch

catch(Exception& e) {

ClientSocket->Close();

::MessageBox(0, e.Message.c_str(),

"Error", MB_ICONERROR);

}

}

}

delete WskStream;

WskStream=NULL;

::Sleep(100);

}

//At ServerSocket's OnGetThread event to new a thread to communication with the requested client

void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender,

TServerClientWinSocket *ClientSocket,

TServerClientThread *&SocketThread)

{

SocketThread = new SrvThread(ClientSocket);

}

The metioned-written codes is used to test a hardware.It can be run correctly.As many different applications,so you only reference it and could not be copy completely.It is important to know the principle of TServerSocket,TClientSocket and how VCL wraps the socket api.This article only provides the support of TCP protocol.The next article I will write will accomplish TCP and UDP protocol,please pay your attention for it.At this time,I would like to thank jishiping(JSP) and Raptor for their help.Thanks for browsing it.I am can be contacted via e-mail:kingcaiyao@163.com

以上程序可以实现服务器与客户端之间的双向通讯,只用一个端口,其工作原理类似于IE,由客户端主动发起连接,服务器端在收到数据包后进行处理,然后根据已建立起的链路,再将数据回写到客户端。在同处在两台局域网的机器上以及一台处于局域,而另一台处于公网的机器上都测试通过。还有我从去年起开始接触网络编程,中间得到jishiping,Raptor的指点和帮助,在此再次感谢他们。

补充说明一点,我将代码经过Notepad编辑后copy到这里的时,发现所有的注释部分都加了一个file:,因此当你看到file:前缀时,那就是注释,并非代码,特此声明

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有