SOCKET编程里,一个客户端向两个服务端和客户端开发(IP和端口号不同)发送消息

面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)
面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)
发布时间: 7:34:19
编辑:www.fx114.net
本篇文章主要介绍了"面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)",主要涉及到面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)方面的内容,对于面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)感兴趣的同学可以参考一下。
要写网络程序就必须用Socket,这是程序员都知道的。而且,面试的时候,我们也会问对方会不会Socket编程?一般来说,很多人都会说,Socket编程基本就是listen,accept以及send,write等几个基本的操作。是的,就跟常见的文件操作一样,只要写过就一定知道。&对于网络编程,我们也言必称TCP/IP,似乎其它网络协议已经不存在了。对于TCP/IP,我们还知道TCP和UDP,前者可以保证数据的正确和可靠性,后者则允许数据丢失。最后,我们还知道,在建立连接前,必须知道对方的IP地址和端口号。除此,普通的程序员就不会知道太多了,很多时候这些知识已经够用了。最多,写服务程序的时候,会使用多线程来处理并发访问。&我们还知道如下几个事实:1。一个指定的端口号不能被多个程序共用。比如,如果IIS占用了80端口,那么Apache就不能也用80端口了。2。很多防火墙只允许特定目标端口的数据包通过。3。服务程序在listen某个端口并accept某个连接请求后,会生成一个新的socket来对该请求进行处理。&于是,一个困惑了我很久的问题就产生了。如果一个socket创建后并与80端口绑定后,是否就意味着该socket占用了80端口呢?如果是这样的,那么当其accept一个请求后,生成的新的socket到底使用的是什么端口呢(我一直以为系统会默认给其分配一个空闲的端口号)?如果是一个空闲的端口,那一定不是80端口了,于是以后的TCP数据包的目标端口就不是80了--防火墙一定会组织其通过的!实际上,我们可以看到,防火墙并没有阻止这样的连接,而且这是最常见的连接请求和处理方式。我的不解就是,为什么防火墙没有阻止这样的连接?它是如何判定那条连接是因为connet80端口而生成的?是不是TCP数据包里有什么特别的标志?或者防火墙记住了什么东西?
&后来,我又仔细研读了TCP/IP的协议栈的原理,对很多概念有了更深刻的认识。比如,在TCP和UDP同属于传输层,共同架设在IP层(网络层)之上。而IP层主要负责的是在节点之间(End to End)的数据包传送,这里的节点是一台网络设备,比如计算机。因为IP层只负责把数据送到节点,而不能区分上面的不同应用,所以TCP和UDP协议在其基础上加入了端口的信息,端口于是标识的是一个节点上的一个应用。除了增加端口信息,UPD协议基本就没有对IP层的数据进行任何的处理了。而TCP协议还加入了更加复杂的传输控制,比如滑动的数据发送窗口(Slice Window),以及接收确认和重发机制,以达到数据的可靠传送。不管应用层看到的是怎样一个稳定的TCP数据流,下面传送的都是一个个的IP数据包,需要由TCP协议来进行数据重组。&所以,我有理由怀疑,防火墙并没有足够的信息判断TCP数据包的更多信息,除了IP地址和端口号。而且,我们也看到,所谓的端口,是为了区分不同的应用的,以在不同的IP包来到的时候能够正确转发。&TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如Win32编程接口一样,TCP/IP也必须对外提供编程接口,这就是Socket编程接口--原来是这么回事啊!&在Socket编程接口里,设计者提出了一个很重要的概念,那就是socket。这个socket跟文件句柄很相似,实际上在BSD系统里就是跟文件句柄一样存放在一样的进程句柄表里。这个socket其实是一个序号,表示其在句柄表中的位置。这一点,我们已经见过很多了,比如文件句柄,窗口句柄等等。这些句柄,其实是代表了系统中的某些特定的对象,用于在各种函数中作为参数传入,以对特定的对象进行操作--这其实是C语言的问题,在C++语言里,这个句柄其实就是this指针,实际就是对象指针啦。&现在我们知道,socket跟TCP/IP并没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以,socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write等等。&现在我们明白,如果一个程序创建了一个socket,并让其监听80端口,其实是向TCP/IP协议栈声明了其对80端口的占有。以后,所有目标是80端口的TCP数据包都会转发给该程序(这里的程序,因为使用的是Socket编程接口,所以首先由Socket层来处理)。所谓accept函数,其实抽象的是TCP的连接建立过程。accept函数返回的新socket其实指代的是本次创建的连接,而一个连接是包括两部分信息的,一个是源IP和源端口,另一个是宿IP和宿端口。所以,accept可以产生多个不同的socket,而这些socket里包含的宿IP和宿端口是不变的,变化的只是源IP和源端口。这样的话,这些socket宿端口就可以都是80,而Socket层还是能根据源/宿对来准确地分辨出IP包和socket的归属关系,从而完成对TCP/IP协议的操作封装!而同时,放火墙的对IP包的处理规则也是清晰明了,不存在前面设想的种种复杂的情形。&明白socket只是对TCP/IP协议栈操作的抽象,而不是简单的映射关系,这很重要!&1、TCP连接手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。&建立起一个TCP连接需要经过“三次握手”:第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”。注:ACK为1表示确认号有效,为0表示报文中不包含确认信息,忽略确认号字段SYN:TCP连接的第一个包,非常小的一种数据包。SYN 攻击包括大量此类的包,由于这些包看上去来自实际不存在的站点,因此无法有效进行处理。
&断开经历的”四次握手“当一方断开断开连接时,会向对方发送一个FIN包;对方在收到FIN包后,会发送一个ACK确认包,因此,通常来说双向连接需要从每个TCP端点发送一对FIN和ACK即四次握手
2、HTTP连接&HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。&HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。&1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。2)在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。&
3、SOCKET原理3.1套接字(socket)概念套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。&应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务转自:/riacool/archive//1905404.html
void CADlg::OnButton1()
CSocket jin,
jin.Create(6666);
jin.Listen(5);
jin.Accept(she);
void CADlg::OnButton1()
jin.Create();
jin.Connect(&127.0.0.1&,6666);
服务端的 jin.Accept(she); 处于阻塞状态;而客户端jin.Connect(&125.74.66.77&,6666);唤醒服务端的阻塞
2、#define&SERVER_MESSAGE&WM_USER+100&&//服务器端消息代号
#define&CLIENT_MESSAGE&WM_USER+101&&//客户端消息代号
3、afx_msg LRESULT OnServerMessage(WPARAM wParam,LPARAM lParam)和ON_MESSAGE(SER_MESSAGE,OnServerMessage):ON_MESSAGE(SER_MESSAGE,OnServerMessage) 这只是填写消息影射表的时候,用到的一个宏,也就是使SER_MESSAGE消息,和OnServerMessage函数相关联。是你触发了这个SER_MESSAGE消息,然后调用OnServerMessage(WPARAM wParam,LPARAM lParam) 处理函数。
4、sock_addr.sin_addr.S_un.S_addr=inet_addr(IpAddressTemp.GetBuffer(0)); //如果在自己电脑上通信,ip必须为本机的:inet_addr(&192.168.1.106&);或者:设置成本地机器的回路127.0.0.1
5、typedef CList&SOCKET,SOCKET&& SOCKET_ARRAY;解释:
在C++中,上述类型定义中CList是一个模板类型名,该模板类型需要两个占位符:SOCKET和SOCKET&,做为实例化该类的对象时使用。比如:声明一个模板类对象的语句为CList&Socket,Socket&& ob_其中Socket为已经定义好了的类型名,对象ob_client实例化以后,类CList中所有定义为SOCKET和SOCKET&的地方将分别被Socket和Socket&所代替。
如下图所示:TP-Linker 中输入192.168.1.1,转发规则-&虚拟服务器,如果你需要在不同的无线网络中都能使用你自己的TCP/IP编程,那么你需要将你的端口号和路由器分给你的IP号绑定起来,那么其他用户都可以通过这个端口号和IP地址和你进行通信了。
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:对于Socket编程,网上资料、博文一抓一大把,不过大多数都是简单讲解单客户端和服务端通信的实例,这里主要给大家展现一下在.net平台上用窗体程序实现的过程,不过比较有特点的是会告诉大家如何实现不同客户端之间的通信,它们如何通过一个服务端准确的找到对方进行通信,包括上线提醒、私信交流、昵称重名处理等功能。
一.服务端架构
1.开启监听
简单来说,服务端首先要创建一个监听线程,检测客户端的连接情况,这个部分的程序封装在一个按钮里。主要实现代码如下:
Thread threadwatch = null;
threadwatch = new Thread(watchconnecting);
threadwatch.IsBackground = true;
threadwatch.Start();
如果有仔细看我上面给出的代码细心的观众会发现有个watchconnecting()方法被委托进了监听线程,其实这就是一个监听客户端信息消息的函数,很老套的过程:
Socket connection = null;
while (true)
connection = socketwatch.Accept();
Socket socketwatch = null;
也只是大家异常熟悉的Socket套接字,这部分绑定IP和端口到Point,然后
socketwatch.Bind(point);
socketwatch.Listen(20);
的过程应该在前面服务端开启监听线程的按钮里实现,这里就不细说了。
然后创建一个通信线程,对服务端和客户端之间的交流进行一个完善:
ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
Thread thread = new Thread(pts);
thread.IsBackground = true;
thread.Start(connection);
2.服务端通信过程
由之前代码里创建的通信线程里委托的recv()方法,看字面意思也知道是接收客户端发送消息的接收函数。也是很常规的部分:
Socket socketServer = socketclientpara as S
while (true)
byte[] arrServerRecMsg = new byte[1024 * 1024];
int length = socketServer.Receive(arrServerRecMsg);
string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(strSRecMsg);
注意,将接收到的信息转化为二进制流之后可以Send(bytes)转发消息了,当然,这一块之后会细讲,这里只是先大概介绍下流程。
二.客户端架构
由于客户端基本架构和服务端大体相似,只是在监听部分转为尝试连接部分,大家记住这两个变量:
Thread threadclient = null;
Socket socketclient = null;
和服务端大同小异,不过注意要在客户端绑定的是之前在服务端绑定的相同IP和端口才能互通,同样将IP和端口绑定到Point上:
socketclient.Connect(point);
即服务端是Accept,客户端是Conncet,然后同样开启一个监听服务端的线程:
threadclient = new Thread(recv);
threadclient.IsBackground = true;
threadclient.Start(socketclient);
至于里面的recv,和前面的服务端完全一样,就不重述了。
三.获取本地IP4的方法
大家是否为如何精确获得IP4的IP地址烦恼呢,又不想手动去查,好吧,这里有一个方法送给大家:
public static string GetLocalIP()
string HostName = Dns.GetHostName();
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i & IpEntry.AddressList.L i++)
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
return IpEntry.AddressList[i].ToString();
return "";
catch (Exception ex)
MessageBox.Show("获取本机IP出错:" + ex.Message);
return "";
四.服务端转发消息
1.转发处理
这个部分即为本文的核心所在,之前铺垫的也都是大家或多或少都了解的,而这个部分我在网上浏览资料时并没有发现比较鲜明的介绍。
首先注意这两个字典集:
Dictionary&string, Socket& dic = new Dictionary&string, Socket& { };
Dictionary&string, string& dicName = new Dictionary&string, string& { };
我们的服务端在客户端连接上服务端时是有办法知道客户端的信息的:
IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).A
int clientPort = (connection.RemoteEndPoint as IPEndPoint).P
RemoteEndPoint = connection.RemoteEndPoint.ToString();
至于为什么我会建立两个字典集,dic里保存的是
RemoteEndPoint = connection.RemoteEndPoint.ToString()
connection = socketwatch.Accept()
RemoteEndPoint是套接字Socket里的一个属性,能唯一的辨识出不同客户端连接时套接字的网络节点,当然,如果有其他类似的属性也可以代替。则RemoteEndPoint 就是Connection的唯一身份标识,那么我们在进行Socket里面一些属性操作时,比如用connection 发送、接收消息都可以以RemoteEndPoint 这个标识来鉴别身份。
不过每个客户端都能自己给自己起个好听的昵称,不然全是网络节点号也记不住,分不清哪个是自己,所以我又用了dicName把网络节点号和客户端的昵称绑在了一起,相当于实现了一个双层的嵌套;
要查找对应信息建议使用LINQ,十分简单,比如:
var name = dicName.Where(q =& q.Value == socketServer.RemoteEndPoint.ToString()).Select(q =& q.Key)
string leavemsg = name.FirstOrDefault()
就可以轻松找出已知某个网络节点号的昵称。
所以服务端转发消息就是当接收到一个客户端传来的消息时会自动将接受到的任何消息转发到其他所有客户端,这个在字典集里遍历就可以实现,比如:
//转发消息给其他客户端
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(strSRecMsg)
foreach (string Client in dicName.Values)
if (Client != socketServer.RemoteEndPoint.ToString())
dic[Client].Send(bytes)
要注意的是,将客户端消息存进字典里的代码是要写在服务端开启监听登录的按钮里,这样每次客户端一连接成功就会记录一次。
2.区别客户端
也许有人会问,虽然转发实现了,但是那么多客户端之间发送的消息如何辨别呢,这里有两种处理方法:可以在服务端设置一个变量保存每一个连接时客户端的昵称,在转发消息时将这个变量放在消息头,这样就可以区分;不过我认为这个方法还是比较麻烦的,既然消息来源是客户端,那我们就在客户端发送的消息头加上每个客户端自己的昵称,这样所有客户端发送的消息都是带有自己的昵称的,这样就不需要我们再过多的处理了。
五.上线下线提醒
其实方法很简单,只要知道了转发的实现很容易想到,只要在客户端开启监听服务的按钮里写一段发送昵称消息给服务端的代码:
byte[] name = Encoding.UTF8.GetBytes(textBoxName.Text)
//调用客户端套接字发送字节数组
socketclient.Send(name)
服务端监听客户端端登录时,会收到来自客户端发出的昵称消息,服务端将昵称存进字典集里就将昵称转发到其他客户端提醒“XXX,上线了”:
string msg = strRecMsg +","+"上线了";
byte[] Msg = Encoding.UTF8.GetBytes(msg);
foreach (string Client in dicName.Values)
if (Client != RemoteEndPoint)
dic[Client].Send(Msg);
下线,我的处理是全部放在套接字监听连接中断异常里,即,只要Socket中断或者连接失败,就会在异常里转发下线消息:
catch (Exception ex)
道理和上线差不多,只是代码的位置不同。
六.昵称重名处理
由前面的介绍,我们互道客户端在连接服务端时会发送一个昵称消息给服务端,服务端将昵称存起来后如果发现字典集里有相同的名字则会关闭正在通信Sock,发送一个提示消息给客户端:
byte[] RecMsg = new byte[1024 * 1024];
int length = connection.Receive(RecMsg);
string strRecMsg = Encoding.UTF8.GetString(RecMsg, 0, length);
if (dicName.Count&0)
string ack = "昵称已存在,请重新输入昵称";
byte[] ackMsg = Encoding.UTF8.GetBytes(ack);
if (dicName.ContainsKey(strRecMsg))
Flag = true;
connection.Send(ackMsg);
connection.Close();
相应的,客户端在受到服务端传过来的提示消息时,关闭Sock下线:
string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length)
string []s=strRevMsg.Split(',')
if (s[0] != textBoxName.Text)
if (strRevMsg == "昵称已存在")
socketServer.Close()
this.buttonStart.Enabled = true
这里有两个要特别注意的地方,首先是if (s[0] != textBoxName.Text)是针对之前的上线提醒,在昵称重名时不提醒上线消息,我们接着看一段客户端开启监听的代码:
//SocketException exception
this.buttonStart.Enabled = false
//定义一个套接字监听
socketclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
//获取文本框中的IP地址
IPAddress address = IPAddress.Parse(textBoxIP.Text.Trim())
//将获取的IP地址和端口号绑定在网络节点上
IPEndPoint point = new IPEndPoint(address, int.Parse(textBoxPort.Text.Trim()))
很显然,我们在点击开启监听的按钮后,按钮会置灰,这也是一种将Socket连接状态反应在按钮上的一个同步,所以当Socket断开时,我们需要this.buttonStart.Enabled =这样才能重新点击按钮,输入正确要求的昵称再重新连接服务端。
之前服务端转发实现的只是群聊,那么私聊怎么办呢。
其实也很简单,我这里以服务端和其他不同客户端私聊为例。
因为能分辨不同的客户端,那么想和谁私聊不是轻松的很。
我的做法是将dicName的消息展示到一个ListBox里:
void OnlineList_Disp(string Info)
if(!listBoxOnlineList.Items.Contains(Info))
listBoxOnlineList.Items.Add(Info);
在服务端想私聊时,只要点击列表里一个客户端,将代码写在一个按钮里,详细实现如下:
string sendMsg = "管理员:"+richTextBoxSend.Text.Trim()
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg)
if (listBoxOnlineList.SelectedIndex == -1)
MessageBox.Show("请选择要发送的客户端!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Stop)
string selectClient = listBoxOnlineList.Text
var point = dicName.Where(q =& q.Key == selectClient).Select(q =& q.Value)
dic[point.FirstOrDefault()].Send(bytes)
richTextBoxSend.Clear()
如果客户端之间想自己私聊呢,其实完全可以衍变过去不是吗,那我就把客户端接收上线提醒的昵称存到一个字典里进行类似操作不是也可以?所以方法都是通的,甚至可以像QQ、微信那样设计,在点击一个字典里的信息时跳转个页面到大对话框不也是美滋滋。
如果有时间,我会尝试突破局域网的限制,实现外网之间Socket通信,目前思路有两个:花生壳内网映射,去阿里云租个外网服务器,当然这些都是后话了,有机会再一起探讨~
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3094次
排名:千里之外
(1)(2)(1)(1)决定你人生高度的,不是你的才能,而是你的态度
收藏,1608 浏览
最近项目中有用到中移动的物联卡,PHP服务端对接该服务能力,需要使用PHP Socket来调用中移动提供的C程序接口能力,所以研究了下PHP Socket。这里为大家详细解释下PHP Socket编程,附带PHP Socket运行示例
Socket用于进程间通信。进程间通信通常基于客户端—服务端模型。此时,客户端—服务端是可以彼此交互的应用程序。客户端和服务端之间的交互需要连接。Socket编程负责的就是为应用程序之间建立可进行交互的连接。
在本文中,我们将学习如何用PHP创建一个简单的客户端—服务端。我们还将学习如何客户端应用程序如何发送消息到服务端,以及如何从服务端接受消息。
目的:开发一个客户端用于发送string消息到服务端,服务端将相同的信息反转后返回给客户端。
第1步:设置变量,如“主机”和“端口”
$host = "127.0.0.1";
$port = 5353;
// No Timeout
set_time_limit(0);
端口号可以是之间的任何正整数。
第2步:创建socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket");
第3步:绑定socket到端口和主机
创建的socket资源绑定到IP地址和端口号。
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket");
第4步:启动socket监听
在绑定到IP和端口后,服务端开始等待客户端的连接。在没有连接之前它就一直等下去。
$result = socket_listen($socket, 3) or die("Could not set up socket listener");
第5步:接受连接
这个函数会接受所建的socket传入的连接请求。在接受来自客户端socket的连接后,该函数返回另一个socket资源,实际上就是负责与相应的客户端socket通信。这里的“$spawn”就是负责与客户端socket通信的socket资源。
$spawn = socket_accept($socket) or die("Could not accept incoming connection");
到现在为止,我们已经准备好了服务端socket&,但实际上这个脚本并没有做任何事情。所以为了继续完成上述目标,我们将读取客户端socket消息,然后将接收到的消息反转后发回给客户端socket。
第6步:从客户端socket读取消息
$input = socket_read($spawn, 1024) or die("Could not read input");
第7步:反转消息
$output = strrev($input);
第8步:发送消息给客户端socket
socket_write($spawn, $output, strlen ($output)) or die("Could not write output");
第9步:关闭socket
socket_close($spawn);
socket_close($socket);
这就完成了服务端。现在,我们学习如何创建PHP客户端。
前两个步骤与服务端相同。
第1步:设置变量,如“主机”和“端口”
$host = "127.0.0.1";
$port = 5353;
// No Timeout
set_time_limit(0);
注:这里的端口和主机应该和服务端中的定义是相同的。
第2步:创建socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket");
第3步:连接到服务端
$result = socket_connect($socket, $host, $port) or die("Could not connect toserver");
此时和服务端不同,客户端socket不绑定端口和主机。相反,它连接到服务端socket,等待接受来自客户端socket的连接。这一步建立了客户端socket到服务端socket的连接。
第4步:写入服务端socket
socket_write($socket, $message, strlen($message)) or die("Could not send data to server");
在此步骤中,客户端socket的数据被发送到服务端socket。
第5步:阅读来自服务端的响应
$result = socket_read ($socket, 1024) or die("Could not read server response");
echo "Reply From Server
第6步:关闭socket
socket_close($socket);
完整的代码
服务端(server.php)
$host = "127.0.0.1";
$port = 25003;
set_time_limit(0);
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket");
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket");
$result = socket_listen($socket, 3) or die("Could not set up socket listener");
$spawn = socket_accept($socket) or die("Could not accept incoming connection");
$input = socket_read($spawn, 1024) or die("Could not read input");
$input = trim($input);
echo "Client Message : ".$
$output = strrev($input);
socket_write($spawn, $output, strlen ($output)) or die("Could not write output");
socket_close($spawn);
socket_close($socket);
客户端(client.php)
= "127.0.0.1";
$message = "Hello Server";
echo "Message To server :".$
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket");
$result = socket_connect($socket, $host, $port) or die("Could not connect to server");
socket_write($socket, $message, strlen($message)) or die("Could not send data to server");
$result = socket_read ($socket, 1024) or die("Could not read server response");
echo "Reply From Server
:".$ socket_close($socket);
建立上述文件(server.php和client.php)后,执行如下操作:
复制www目录中的这些文件(假设WAMP),安置于C:wamp。
打开Web浏览器,在地址栏中键入localhost&。
先浏览server.php然后client.php。
原文链接:,转发请注明来源!
小灰灰推荐
小灰灰博客,社交类新博客,分享互联网开发的技术与经验。
生命在于分享,欢迎有技术、有经验、有问题、有态度、有故事的你前来分享!

我要回帖

更多关于 服务端和客户端开发 的文章

 

随机推荐