设为首页 收藏本站
查看: 711|回复: 0

[经验分享] Windows Socket编程

[复制链接]

尚未签到

发表于 2016-5-23 06:53:32 | 显示全部楼层 |阅读模式
Windows Socket编程
一、基于TCP(面向连接)的socket编程
服务器端程序:
1、创建套接字(socket)。
2、将套接字绑定到一个本地地址和端口上(bind)。
3、将套接字设为监听模式,准备接受客户请求(listen)。
4、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。
5、用返回的套接字和客户端进行通信(send/recv)。
6、返回,等待另一客户请求。
7、关闭套接字。
客户端程序:
1、创建套接字(socket)。
2、向服务器发出连接请求(connect)。
3、和服务器端进行通信(send/recv)。
4、关闭套接字。

二、基于UDP(面向无连接)的socket编程
服务器端(接受端)程序:
1、创建套接字(socket)。
2、将套接字绑定到一个本地地址和端口上(bind)。
3、等待接收数据(recvfrom)。
4、关闭套接字。
客户端(发送端)程序:
1、创建套接字(socket)。
2、向服务器发送数据(sendto)。
3、关闭套接字。
其实对于建立连接后,可以相互发送信息,无所谓谁是服务器,谁是客户端。在开始的时候,一定是bind的一段,接收数据,这是死的。对于服务器和客户是在开始的时候划分的。


三、建立MFC的控制台应用程序,编写基于TCP/IP的服务器端应用。

1、int WSAStartup(
  WORD wVersionRequested,  
  LPWSADATA lpWSAData  
);
wVersionRequested的高位字节说明了socket的副版本号,低位字节说明了socket的主版本号。
LPWSADATA lpWSAData  指向WSADATA数据结构的指针,其中包含多个字段。
WSAStartup是socket应用程序调用的第一个函数,用于加载WindowsSockets版本号和WindowsSockets执行的细节参数。
具体代码如下:
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )return;

2、创建socket套接字
SOCKET socket(
  int af,      
  int type,     
  int protocol  
);
socket函数产生一个socket描述符和相关资源,和特定的协议联系。
af表示协议族,如果是TCP/IP or UDP协议,af等于AF_INET
type表示使用什么类型的socket,有三种SOCK_STREAM,SOCK_DGRAM,SOCK_RAW
如果是编写基于tcp的应用,使用SOCK_STREAM
如果编写基于udp的应用,使用SOCK_DGRAM.
protocol默认设为0。具体代码:
SOCKET SockSrv=socket(AF_INET,SOCK_STREAM,0);
………127.0.0.1本地回路地址,在本机器上发消息……………………

3、在服务器端将socket和地址、端口绑定。
int bind(
  SOCKET s,                          
  const struct sockaddr FAR *name,   
  int namelen                        
);
bind函数把产生的socket和指定的地址,端口联系起来,在服务器端使用。其中sockaddr(or SOCKADDR)用于存储ip地址结构(服务器的地址和端口),具体定义为:
struct sockaddr {
    unsigned short sa_family;
    char           sa_data[14];
};
sa_family表示使用的socket地址族,sa_data[14]定义了socket地址结构的最大存储单元。为了更详细的指定socket地址,可以使用SOCKADDR_IN 数据结构,它细分了TCP/IP Sockets 的地址字段,在程序中可以分别给每位字段赋预定的值,最后在bind时,进行SOCKADDR的强制转换,因为SOCKADDR和SOCKADDR_IN结构大小相等。
struct sockaddr_in{
    short            sin_family;
    unsigned short      sin_port;
    struct   in_addr      sin_addr;
    char               sin_zero[8];
};
struct   in_addr {
    union   {
         struct{
             unsigned  char   s_b1,
                              s_b2,
                              s_b3,
                              s_b4;
        }  S_un_b;
             struct  {
             unsigned  short  s_w1,
                              s_w2;
              }  S_un_w;
               unsigned long  S_addr;
     } S_un;
};
在sockaddr中除sin_family外,其他都是网络字节顺序表示,因此需要显示转换数据的字节顺序,把主机上的字节顺序变换为网络的字节顺序。其中u_short htons(
  u_short hostshort  
);
是转换无符号短整型数。用于端口号的转换。
u_long htonl(
  u_long hostlong  
);
是转换无符号长整型数。用于S_addr的转换。
namelen表示地址结构的长度。sizeof(sockaddr)即可得到。
具体代码如下:
SOCKADDR_IN addrSRV;
addrSRV.sin_family=AF_INET;
addrSRV.sin_addr.S_un.S_addr=ADDR_ANY;
addrSRV.sin_port=htons(6000);
bind(SockSrv,(SOCKADDR*)&addrSRV,sizeof(SOCKADDR));
ADDR_ANY表示不详细指定具体的网卡ip地址,它也不需要字节顺序转换,因为值为0,对于非零值则一定需要转换。

4、设置socket为监听模式
int listen(
  SOCKET s,   
  int backlog  
);
s表示待设定的socket,backlog表示队列的最大等待数。
具体代码如下:
listen(SockSrv,10);

5、开始接受来自客户端的请求
SOCKET accept(
  SOCKET s,
  struct sockaddr FAR *addr,  
  int FAR *addrlen  
);
s是处于监听状态的socket,*addr是请求连接的客户端的地址信息,*addrlen 是客户端地址结构的长度。返回一个socket,然后可以使用返回的socket和客户端通信。
具体代码如下:
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
SOCKET SockConn=accept(SockSrv,(SOCKADDR*)&addrClient,&len);
这里的len必须进行初始化,否则会产生错误。

6、发送信息给客户端
int send(
  SOCKET s,              
  const char FAR *buf,  
  int len,               
  int flags              
);
s是应答上客户端的socket,即使用accept返回的socket。
*buf保存要传送给客户端的信息,是一个字符指针。
len保存字符数组的长度。
flags指定函数调用的方式。默认使用0。
具体代码如下:
send(SockConn,"Welcome to www.sun.com!",sizeof("Welcome to www.sun.com!")+1,0);

7、接收来自客户端的信息
int recv(
  SOCKET s,      
  char FAR *buf,  
  int len,        
  int flags      
);
s是和客户端通信的socket
*buf存放接收的信息
len存放buf的大小
flags指定函数的调用方式,默认为0。
具体代码如下:
char recvBuf[100];
recv(SockConn,recvBuf,100,0);
printf("%s\n",recvBuf);

8、通信完毕后要关闭socket
int closesocket(SOCKET s  );
具体代码如下:
closesocket(SockConn);

还要在程序的最后关闭WSA
int  WSACleanup (void);
所以int WSAStartup(
  WORD wVersionRequested,  
  LPWSADATA lpWSAData  
);
和int  WSACleanup (void);成对出现。
对于以上的函数,要求包含Winsock2.h头文件,同时连接时使用Ws2_32.lib库(在工程->设置--->连接  中加入库文件);否则,编译运行会产生错误。


9、总结:
      首先要了解socket编程的原理,在原理的指导下,每一个通信的步骤都对应Windows Socket的一个函数,调用函数完成预定的通信。

四、编写基于TCP/IP的客户端应用程序。
1、加载Windows Socket版本
int WSAStartup(
  WORD wVersionRequested,  
  LPWSADATA lpWSAData  
);
typedef struct WSAData {
  WORD                  wVersion;
  WORD                  wHighVersion;
  char                  szDescription[WSADESCRIPTION_LEN+1];
  char                  szSystemStatus[WSASYS_STATUS_LEN+1];
  unsigned short        iMaxSockets;
  unsigned short        iMaxUdpDg;
  char FAR *            lpVendorInfo;
} WSADATA, *LPWSADATA;

成功加载返回0。wVersionRequested的高位字节说明了socket的副版本号,低位字节说明了socket的主版本号。
2、创建socket套接字
SOCKET socket(
  int af,      
  int type,     
  int protocol  
);
SOCKET SockClient=socket(AF_INET,SOCK_STREAM,0);

3、使用socket套接字发送建立请求
int connect(
  SOCKET s,                          
  const struct sockaddr FAR *name,  
  int namelen                        
);
其中s是客户端的套接字,*name存储要连接到的服务器端的地址信息,在此函数之前要详细说明各字段的值。
具体代码如下:
SOCKADDR_IN SockSrv;
SockSrv.sin_family=AF_INET;
SockSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
SockSrv.sin_port=htons(6000); connect(SockClient,(SOCKADDR*)&SockSrv,sizeof(SOCKADDR));
inet_addr()是将ip地址字符串转换成适合IN_ADDR 结构的ip地址。

4、接收来自服务器端的信息。
具体代码如下:
char recvBuf[100];
recv(SockClient,recvBuf,100,0);
printf("%s\n",recvBuf);

5、发送信息给服务器。
send(SockClient,"I am chenlei!",sizeof("I am chenlei!")+1,0);
6、可以继续发送和接收。
7、通信完毕关闭socket
int closesocket(SOCKET s  );
具体代码如下:
closesocket(SockClient);
还有相关操作和服务器端的一样。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chenlei5662/archive/2008/08/20/2801228.aspx

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-220450-1-1.html 上篇帖子: SQL Server 2008 R2 性能计数器详细列表(三) 下篇帖子: Microsoft Silverlight Tools Beta 2 for Visual Studio 2008 下载地址
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表