最近段时间一直忙至C/S架构模式的项目形式,把一些想法和认识记录下来
1、客户机和服务器这种模式在操纵过程中采取的是主动接收请求的方式。
服务器端:
首先是服务器端要先启动,并根据请求提供相应的服务:
(1)打开一个通信通道并告知本地主机,它愿意在某一地址和端口上接收客户机。
(2)等待客户端的的请求到达该端口。
(3)接收到重复服务请求,处理该请求并发送应答信号。接收并处理后发送服务请求,需要激活一个新的进程( 或线程)来处理这个客户请求,并不需要对其它请求做出应答。服务完成后,关闭此新进程和客户通信链路,并终止。
(4)返回第二步,等待另一客户请求。
客户方:客户方是在这种模式中,采取的是主动发送请求的方式。
(1) 打开一个通信通道,并连接 到服务器所在主机的特定端口。、
(2) 向服务器发送服务请求报文,等待并接收应答;继续发送请求
(3) 请求结束之后关闭通信通道并终止。
根据上述的架构模式来让我理解下:
(一) 基于TCP(面向连接)的socket编程
服务端程序:
1、创建套接字。(socket函数)
2、将套接字绑定到一个本地地址和端口上。(bind函数)
3、将套接字设置为监听模式,并准备接收客户请求。(listen函数)
4、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此连接的套接字。(accept)
5、用返回的套接字客户端进行通信。(send、recv函数)、
6、返回,等待另一个客户请求。
7、关闭套接字。(close)
客户端程序:
1、创建套接字(socket)。
2、向服务器发出连接请求。(connect函数)
3、和服务器进行通信。(send、recv函数)
4、关闭套接字。
//示例代码:
Client:
#include<WinSock2.h>
#include <stdio.h>
int main(){
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0){
return 0;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
return 0;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(addrSrv));
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
send(sockClient,"this is lizi ",strlen("this is lizi ")+1,0);
closesocket(sockClient);
WSACleanup();
return 0;
}
Server:
#include<WinSock2.h>
#include <stdio.h>
int main(){
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0){
return 0;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
return 0;
}
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
bind(sockSrv,(sockaddr*)(&addrSrv),sizeof(addrSrv));
listen(sockSrv,5);
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR_IN);
while (1)
{
SOCKET sockConn=accept(sockSrv,(SOCKADDR*)(&addrClient),&len);
char sendBuf[1024];
//把一个字符串数组格式化到sendBuf数组里
sprintf(sendBuf,"welcom %sto c++",inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100];
recv(sockConn,recvBuf,100,0);
printf("%s\n",recvBuf);
closesocket(sockConn);
}
return 0;
}
/
(二) 基于UDP(无连接)的socket编程
服务端(接收方)程序:
1、创建套接字(socket)。
2、将套接字绑定到一个本地地址和端口上(bind)
3、等待接收数据(recvfrom)
4、关闭套接字。
客户端(发送方)程序:
1、创建套接字。socket
2、向服务器发送数据sendto
3、关闭套接字。
///
实例代码:
client:
#include<WinSock2.h>
#include <stdio.h>
int main(){
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0){
return 0;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
return 0;
}
SOCKET sockServer=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
sendto(sockServer,"hello",strlen("hello")+1,0,(SOCKADDR*)&addrSrv,sizeof(addrSrv));
closesocket(sockServer);
WSACleanup();
return 0;
}
server:
#include<WinSock2.h>
#include <stdio.h>
int main(){
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0){
return 0;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
return 0;
}
SOCKET sockServer=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
bind(sockServer,(SOCKADDR*)(&addrSrv),sizeof(addrSrv));
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR_IN);
char recvBuf[100];
recvfrom(sockServer,recvBuf,100,0,(SOCKADDR*)(&addrSrv),&len);
printf("%s\n",recvBuf);
WSACleanup();
return 0;
}