Windows网络编程:阻塞模式下的Socket编程

Posted Herbert_Zero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows网络编程:阻塞模式下的Socket编程相关的知识,希望对你有一定的参考价值。

一、Socket的含义

  Windows Socket是从UNIX Socket继承发展而来,最新的版本是2.2。进行Windows网络编程,你需要在你的程序中包含WINSOCK2.H或MSWSOCK.H,同时你需要添加引入库WS2_32. LIB或WSOCK32.LIB。

  Socket的英文原意是“孔”或“插座”,怎么会引入到Internet中呢?在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

  所谓Socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

  Sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);基于TCP的socket编程是采用的流式套接字。
  
二、重要的Socket API

  重要的Socket API:java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。

  1. Accept方法用于产生”阻塞”,直到接受到一个连接,并且返回一个客户端的Socket对象实例。”阻塞”是一个术语,它使程序运行暂时”停留”在这个地方,直到一个会话产生,然后程序继续;通常”阻塞”是由循环产生的。

  2. getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例。

  3. getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。 注意:其中getInputStream和getOutputStream方法均可能会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

三、如何开发一个Server-Client模型的程序

  服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。

  客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。

  Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。 Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

四、经典练习:阻塞模式下的Socket编程

下面是一个简单的服务器和客户端示例代码。

1.阻塞模式下的socket编程,总结设计服务器端程序的步骤:
① 初始化Windows Socket;
② 创建一个监听的Socket;
③ 设置服务器地址信息,并将监听端口绑定到这个地址上;
④ 开始监听;
⑤ 接受客户端连接;
⑥ 和客户端通信;
⑦ 结束服务并清理Windows Socket和相关数据,或者返回第4步。

TCPServer部分:

#include <winsock2.h>  
void main(void)

    WSADATA              wsaData;
    SOCKET               ListeningSocket;
    SOCKET               NewConnection;
    SOCKADDR_IN          ServerAddr;
    SOCKADDR_IN          ClientAddr;
    int                  Port = 5150;

    //初始化Windows Socket 2.2  
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    //创建一个新的Socket来监听客户端的连接请求  
    ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //填写服务器地址信息  
    //端口为5150  
    //IP地址为INADDR_ANY,注意使用htonl将IP地址转换为网络格式  
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(Port);
    ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //绑定监听端口  
    bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));

    //开始监听,指定最大同时连接数为5  
    listen(ListeningSocket, 5);

    //接受新的连接  
    NewConnection = accept(ListeningSocket, (SOCKADDR *)&ClientAddr, &ClientAddrLen));

    //新的连接建立后,就可以互相通信了,在这个简单的例子中,我们直接关闭连接  
    //并关闭监听Socket,然后退出应用程序  

    closesocket(NewConnection);
    closesocket(ListeningSocket);

    //释放Windows Socket DLL的相关资源  

    WSACleanup();

2.阻塞模式下的socket编程,总结设计客户端程序的步骤:

① 初始化Windows Socket;
② 创建一个监听的Socket;
③ 设置客户端地址信息,并将监听端口绑定到这个地址上;
④ 向服务器发出连接请求;
⑤ 新的连接建立后,可以互相通信;
⑥ 结束通信时,关闭连接,关闭监听Socket,并释放Windows Socket DLL的相关资源。

TCPClient部分:

    #include <winsock2.h>  
    void main(void)  
      
         WSADATA              wsaData;  
         SOCKET               s;  
         SOCKADDR_IN          ServerAddr;  
         int                  Port = 5150;  

       //初始化Windows Socket 2.2  
       WSAStartup(MAKEWORD(2,2), &wsaData);  
       //创建一个新的Socket来连接服务器  
          s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

       // 填写客户端地址信息  
       // 端口为5150  
       // 服务器IP地址为"136.149.3.29",注意使用inet_addr将IP地址转换为网络格式  
          ServerAddr.sin_family = AF_INET;  
         ServerAddr.sin_port = htons(Port);      
         ServerAddr.sin_addr.s_addr = inet_addr("136.149.3.29");  
       //向服务器发出连接请求  
          connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr));   
       //新的连接建立后,就可以互相通信了,在这个简单的例子中,我们直接关闭连接,  
       //并关闭监听Socket,然后退出应用程序  
          closesocket(s);  
       // 释放Windows Socket DLL的相关资源  
          WSACleanup();  
      

3.小结

socket编程中有一些成对的函数,总结如下:
① 初始化和释放dll相关资源函数,WSAStartup和WSACleanup;
② socket的创建和关闭函数,socket和closesocket;
③ 客户端的connect函数和服务器的accept函数,创建连接和接受连接;
④ 数据通信时的发送数据send函数和接受数据recv函数;
⑤ 注意服务器端程序中创建有两个socket,分工明确,一个监听客户端信息,一个用来协助数据的通信,另外,还有绑定监听端口函数bind,设置连接数函数listen等。

以上是关于Windows网络编程:阻塞模式下的Socket编程的主要内容,如果未能解决你的问题,请参考以下文章

Socket编程模式理解与对比

socket编程模式理解与对比

网络编程基础漫谈之 socket 的阻塞模式和非阻塞模式

windows socket编程阻塞模式下,recv函数返回0?

windows下的6种IO模型

服务器编程心得—— 如何将socket设置为非阻塞模式