TCP服务器和客户机编程

TCP服务器和客户机编程,第1张

服务器(TCP/IP)编程实例
现在大多数语言都支持客户服务器模式(C/S)编程,其中VB给我们提供了很好的客户-服务器编程方式。下面我们用VB来实现TCP/IP网络编程。
TCP/IP协议是Internet最重要的协议。VB提供了WinSock控件,用于在TCP/IP的基础上进行网络通信。当两个应用程序使用Socket进行网络通信时,其中一个必须创建Socket服务器侦听,而另一个必须创建Socket客户去连接服务器。这样两个程序就可以进行通信了。
①创建服务器
首先创建一个服务端口号。并开始侦听是否有客户请求连接。
建立一窗体,并向其增加一个Winsock控件(可在工程菜单中的部件项来添加此控件)
添加两文本框Text1,Text2,和一按钮Command1
Private Sub Form_Load()
SockServerLocalPort = 2000 ′服务器端口号,最好大于1000
SockServerListen ′开始侦听
End Sub
Private Sub Form_Unload(Cancel As Integer)
SockServerClose
End Sub
Private Sub SockServer_Close()
SockServerClose
End Sub
Private Sub SockServer_ConnectionRequest(ByVal requestID As Long)
SockServerClose
SockServerAccept requestID ′表示客户请求连接的ID号
End Sub
′当客户向服务器发送数据到达后,产生DataArrival事件,在事件中接收数据,GetData方法接收数据。
Private Sub SockServer_Data
Arrival(ByVal bytesTotal As Long)
Dim s As String
SockServerGetData s
Text1Text = s
End Sub
当需要向客户发送数据时,只需调用SendData方法。
Private Sub Command1_Click()
SockServer SendData Text2Text
End Sub
②创建客户
要创建客户连接服务器,首先设置服务器主机名,如IP地址、域名或计算机名,然后设置服务器端口,最后连接服务器。
建立一窗体,并向其增加一个Winsock控件(可在工程菜单中的部件项来添加此控件),取名为:SockC1。添加两文本框Text1,Text2,和一按钮Command1
Private Sub Form_Load()
SockClRemoteHost =′127001″
′表示服务器主机名
SockClRemotePort = 2000
  ′表示服务器端口名
SockClConnect
′连接到服务器
End Sub
Private Sub Form_Unload(Cancel As Integer)
SockClClose
End Sub
Private Sub SockCl_Close()
SockClClose
End Sub
Private Sub SockCl_DataArrival(ByVal bytesTotal As Long)
Dim s As String
SockClGetData s ′接收数据到文本框中
Text1Text = s
End Sub
Private Sub Command1_Click()
SockClSendData Text2Text ′向服务器发送数据
End Sub
③进行通信
把这两个窗体分别编译成两个EXE文件,服务器Serverexe和客户Clientexe程序,并把它们分别安装在服务器端和客户端,这样就可以实现两者通信了。
-

如果可以,希望能加我百度好友,共同学习。

DLL文件:

library DLLDPR;

uses

ShareMem,

IdTCPClient;

{$R res}

function linkserver(host: string; port: integer): boolean;

var

tcp: TIdTCPClient;

begin

tcp := tidtcpclientCreate(nil);

tcpHost := host;

tcpPort := port;

try

tcpConnect(1000);

except

end;

result := tcpConnected;

end;

exports

linkserver;

end

EXE文件

function linkserver(host: string; port: integer): boolean;

external 'dlldprdll';

procedure TForm1Button1Click(Sender: TObject);

const

ba: array[boolean] of string = ('失败', '成功');

var

b: boolean;

begin

b := linkserver(edit1Text, strtointdef(edit2Text, 80));

showmessage('连接到' + edit1Text + #13 + ba[b]);

end;

用C#实现多线程TCP协议的服务器端程序:
// <summary>
/// Tcp客户线程类(服务端),ThreadServerProcessor 线程产生的客户连接,用该线程读写
/// </summary>
public class ThreadClientProcessor
{
//Tcp连接实例
private TcpClient tcpClient;
//消息框,本来想写日志用
private SystemWindowsFormsListBox MessageList;
private string Password; //该连接登陆密码
private string Cmd1Echo;
private string Cmd2Echo;
private bool ClientLogOn;//客户是否登陆
private bool TcpClose;
public ThreadClientProcessor(){}
//构造函数,参数解释:Tcp客户,消息框,该服务密码(password命令后的参数) ,命令回应串 1,2
public ThreadClientProcessor(TcpClient client , ListBox listBox,string LogonText ,string cmd1echo,string cmd2echo)
{
ClientListAdd(this); //把当前实例加入一个列表中,方便以后控制
thistcpClient=client;
thisMessageList=listBox;
thisPassword=LogonText;
thisCmd1Echo=cmd1echo;
thisCmd2Echo=cmd2echo;
thisClientLogOn=false;
thisTcpClose=false;
}
public static char[] CmdSplit={' '}; //读来的串由' ' 进行分离,命名+' '+参数
//public const string[] Cmd=new string[] { "password","cmd1","cmd2","echo","bye"};
//该函数由你自己写,这个只是给一个例子,
//功能:命令处理器,给个命令串,返回该命令处理结果,把命令和处理结果放在一个文本文件里,便于系统升级
public string TcpCmd(string s)
{
string result;
try
{
string cmdarg=sTrim();
string[] args=cmdargSplit(CmdSplit);
string cmd=args[0]ToLower();
switch (cmd )
{
case "password" :
if (argsLength>1)
{
ClientLogOn= PasswordEquals(args[1]Trim());
result=ClientLogOn "登陆成功":"密码不正确,未登陆";
}
else result= "登陆时候,没有输入密码";
break;
case "cmd1":
result=ClientLogOnthisCmd1Echo:"该命令无权执行,请先登陆";
break;
case "cmd2":
result=ClientLogOnthisCmd2Echo:"该命令无权执行,请先登陆";
break;
case "echo":
result=stringFormat("服务器回应:\n {0}",s);
break;
case "bye":
thisTcpClose=true;
result="DisConnected";
break;
default:
result="不可识别的命令";
break;
}
}
catch
{
result="解析命令发生错误,你输入的是狗屁命令,TMD ^ ";
}
return result;
} //end cmd
//定义一个线程,该线程对应的函数是 void start()(不是Start())
//一下程序主要是 *** 作该线程
public SystemThreadingThread tcpClientThread;
//启动客户连接线程
public void Start()
{
tcpClientThread=new Thread(new ThreadStart(start));
tcpClientThreadPriority=ThreadPriorityBelowNormal;
tcpClientThreadStart();
}
//断开该当前实例连接,终止线程
public void Abort()
{
if (thistcpClientThread!=null)
{
//tcpClientThreadInterrupt();
tcpClientThreadAbort();
//一定要等一会儿,以为后边tcpClientClose()时候,会影响NetWorkStream的 *** 作
ThreadSleep(TimeSpanFromMilliseconds(100));
tcpClientClose();
}
}
//静态列表,包含了每个连接实例(在构造实例时候使用了 ArrayListAdd( object))
private static SystemCollectionsArrayList ClientList=new ArrayList();
//断开所有的Tcp客户连接,静态方法
public static void AbortAllClient()
{
for(int j=0 ;j< ClientListCount;j++)
{
//从实例列表中取一个对象,转化为ThreadClientProcessor对象
ThreadClientProcessor o=(ThreadClientProcessor ) ClientList[j];
//调用ThreadClientProcessor 对象的停止方法
oAbort();
}
//清除连接列表
ClientListClear();
}
//读写连接的函数,用于线程//
private void start()
{
byte[] buf=new byte[10241024]; //预先定义1MB的缓冲
int Len=0; //流的实际长度
NetworkStream networkStream=tcpClientGetStream(); //建立读写Tcp的流
try
{
byte[] p=EncodingUTF8GetBytes(" 欢迎光临,请输入密码" );
//向Tcp连接写 欢迎消息
if (!thisClientLogOn )
networkStreamWrite(p,0,pLength);
//开始循环读写tcp流
while (!TcpClose)
{
//如果当前线程是在其它状态,(等待挂起,等待终止)就结束该循环
if (ThreadCurrentThreadThreadState!=ThreadStateRunning)
break;
//判断Tcp流是否有可读的东西
if ( networkStreamDataAvailable)
{
//从流中读取缓冲字节数组
Len=networkStreamRead(buf,0,bufLength);
//转化缓冲数组为串
string cmd=EncodingUTF8GetString(buf,0,Len);
thisMessageListItemsAdd("客户机:"+cmd);
//处理该缓冲的串(分析命令),分析结果为res串
string res=TcpCmd(cmd);
//把命令的返回结果res 转化为字节数组
byte[] result=EncodingUTF8GetBytes(res);
//发送结果缓冲数组给客户端
networkStreamWrite(result,0,resultLength);
thisMessageListItemsAdd("服务器回应:"+res);
}
else
{
//ThreadSleep(TimeSpanFromMilliseconds(200d));
//thisMessageListItemsAdd("客户机无命令");
//如果当前Tcp连接空闲,客户端没有写入,则当前线程停止200毫秒
ThreadSleep(TimeSpanFromMilliseconds(200d));
}
}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/13435540.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-08-05
下一篇 2023-08-05

发表评论

登录后才能评论

评论列表(0条)

保存