Wnsock编程初涉

本文介绍了Winsock编程的基础知识,包括客户端和服务端编程流程。详细解释了WSAStartup、socket、connect、bind、listen、accept等关键函数的作用及使用方法。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

Winsock编程
1 客户端编程
a. WSAStartup (MAKEWORD(1,1), &WSAData)
   初始化一个Winsock
   MSDN解释The WSAStartup function initiates use of Ws2_32.dll by a process.
   第一个参数是Winsock支持的最高版本,第二个参数是输出参数,用来获取Winsock的实现细节
   包括支持的版本信息,socket的数目,系统信息等等。
b. ServerSock = socket (AF_INET, SOCK_STREAM, 0)
   Create a TCP/IP socket that is bound to the server.创建一个用来连接server的socket
   有必要看一下socket的定义
   SOCKET socket(
  int af,      
  int type,    
  int protocol 
  );
 af
[in] Address family specification. 这个Address family specification是什么意思,在另一个资料

中查到 must be AF_INET. 与之对应的有一个native address family,这里就不深究了,应该就是IP地

址的表示类型

type
[in] Type specification for the new socket.
The following are the only two type specifications supported for Windows Sockets 1.1: Type

Explanation
SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams with an OOB

data transmission mechanism. Uses TCP for the Internet address family.
SOCK_DGRAM Supports datagrams, which are connectionless, unreliable buffers of a fixed

(typically small) maximum length. Uses UDP for the Internet address family. 
这个参数就是选择TCP还是UDP作为传输层协议

protocol
[in] Protocol to be used with the socket that is specific to the indicated address family.

c. phostent = gethostbyname (HOSTNAME)
   retrieves host information corresponding to a host name from a host database
   什么信息呢,主机的官方名称和host表里的域名
d. 初始化destination_sin,目标服务器的地址信息
   包括使用的address family的类型, 端口, 主机名等
e. connect 建立与特定Socket的链接
   int connect(
  SOCKET s,    还未连接的socket的标识                      
  const struct sockaddr FAR *name,  要连接的socket的地址,包括IP地址和端口号
  int namelen                       
);
f. send 将字符串发送出去
  int send(
  SOCKET s,          链接好的socket    
  const char FAR *buf,  字符串指针
  int len,               长度
  int flags             发送的方式, MSDN中没有介绍
);

g. recv 得到返回的字符串
  int recv(
  SOCKET s,      
  char FAR *buf, 
  int len,       
  int flags      
);
  如果是面向连接的socket,这个socket要事先connect
  如果是无连接的socket,要事先bound,不知道bound的具体含义是什么
  当数据大小超过提供的buffer的大小时,对于链接的socket,sevice provider会保留着个
  数据,直到提供更大的buffer,而对于无连接的socket,超出buffer大小的数据会被丢失
h. 结束处理
  shutdown (ServerSock, 0x00);

  // Close the socket.
  closesocket (ServerSock);

  WSACleanup ();
 
2 服务端
下面是服务端编程应该注意的几个函数

bound
给接受请求的socket指定主机名(IP)和端口,和客户端设置的IP和端口一致

listen
The listen function places a socket a state where it is listening for an incoming

connection.

int listen(
  SOCKET s,    处于监听状态的socket的标识
  int backlog  等待处理的连接的最大个数
);
accept 
用于允许一个连接请求,并建立一个socket
如果没有请求则会一直等待,有点像getmessage
SOCKET accept(
  SOCKET s,      接受请求服务端Socket
  struct sockaddr FAR *addr, out参数,用于接收新建socket的Address
  int FAR *addrlen, 缓冲区的大小
);

Winsock的是传输层之上,应用层之下的编程,与winInet相比,提供了更灵活的处理更底层数据结构的功

能,winInet好像只能处理http和ftp吧,但是winsock上可以自己定义数据格式。
我觉得winsock主要有两类socket,一类是server socket, 用来接收连接请求, 需要调用bound,

listen,accept函数;另一类是用于数据交换的socket, 主要调用connect, recv, send,这类socket

应该有一个输入缓冲区和一个输出缓冲区

下面是客户端和服务端代码,在VC6下通过编译并且显示正确,记住link里面要加上ws2_32.lib
客户端
#include <windows.h>
#include <winsock.h>

#define PORTNUM         5000          // Port number
#define HOSTNAME        "localhost"   // Server name string
                                      // This should be changed
                                      // according to the server.
int WINAPI WinMain (
              HINSTANCE hInstance,    // Handle to the current instance
              HINSTANCE hPrevInstance,// Handle to the previous instance
              LPTSTR lpCmdLine,       // Pointer to the command line
              int nCmdShow)           // Show state of the window
{
  int index = 0,                      // Integer index
      iReturn;                        // Return value of recv function
  char szClientA[100];                // ASCII string
  TCHAR szClientW[100];               // Unicode string
  TCHAR szError[100];                 // Error message string

  SOCKET ServerSock = INVALID_SOCKET; // Socket bound to the server
  SOCKADDR_IN destination_sin;        // Server socket address
  PHOSTENT phostent = NULL;           // Points to the HOSTENT structure
                                      // of the server
  WSADATA WSAData;                    // Contains details of the
                                      // Winsocket implementation

  // Initialize Winsocket.
  if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
  {
    wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    return FALSE;
  }

  // Create a TCP/IP socket that is bound to the server.
  if ((ServerSock = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  {
    wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    return FALSE;
  }

  // Fill out the server socket's address information.
  destination_sin.sin_family = AF_INET;

  // Retrieve the host information corresponding to the host name.
  if ((phostent = gethostbyname (HOSTNAME)) == NULL)
  {
    wsprintf (szError, TEXT("Unable to get the host name. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    closesocket (ServerSock);
    return FALSE;
  }

  // Assign the socket IP address.
  memcpy ((char FAR *)&(destination_sin.sin_addr),
          phostent->h_addr,
          phostent->h_length);

  // Convert to network ordering.
  destination_sin.sin_port = htons (PORTNUM);     

  // Establish a connection to the server socket.
  if (connect (ServerSock,
               (PSOCKADDR) &destination_sin,
               sizeof (destination_sin)) == SOCKET_ERROR)
  {
    wsprintf (szError,
              TEXT("Connecting to the server failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    closesocket (ServerSock);
    return FALSE;
  }

  // Send a string to the server.
  if (send (ServerSock, "gonglong the braveriest soldier", strlen ("gonglong the braveriest

soldier") + 1, 0)
           == SOCKET_ERROR)
  {
    wsprintf (szError,
              TEXT("Sending data to the server failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  }

  // Disable sending on ServerSock.
  shutdown (ServerSock, 0x01);

  for (;;)
  {
    // Receive data from the server socket.
    iReturn = recv (ServerSock, szClientA, sizeof (szClientA), 0);

    // Check if there is any data received. If there is, display it.
    if (iReturn == SOCKET_ERROR)
    {
      wsprintf (szError, TEXT("No data is received, recv failed.")
                TEXT(" Error: %d"), WSAGetLastError ());
      MessageBox (NULL, szError, TEXT("Client"), MB_OK);
      break;
    }
    else if (iReturn == 0)
    {
      MessageBox (NULL, szClientA, TEXT("Client"),
                  MB_OK);
      break;
    }
    else
    {
      // Convert the ASCII string to a Unicode string.
      for (index = 0; index <= strlen (szClientA); index++)
        szClientW[index] = szClientA[index];

      // Display the string received from the server.
      MessageBox (NULL, szClientW, TEXT("Received From Server"), MB_OK);
    }
  }

  // Disable receiving on ServerSock.
  shutdown (ServerSock, 0x00);
  // Close the socket.
  closesocket (ServerSock);

  WSACleanup ();

  return TRUE;
}

服务端
#include <windows.h>
#include <winsock.h>

#define PORTNUM         5000          // Port number
#define HOSTNAME        "localhost"   // Server name string

int WINAPI WinMain (
              HINSTANCE hInstance,    // Handle to the current instance
              HINSTANCE hPrevInstance,// Handle to the previous instance
              LPTSTR lpCmdLine,       // Pointer to the command line
              int nCmdShow)           // Show state of the window
{
  SOCKET ServerSock,              // IR socket bound to the server
         ClientSock;              // IR socket bound to the client

  //SOCKADDR_IRDA address = {AF_IRDA, 0, 0, 0, 0, "IRServer"};
  SOCKADDR_IN server_sin;        // Server socket address
                                  // Specifies the server socket address
  int index = 0,                  // Integer index
      iReturn;                    // Return value of recv function
  char szServerA[100];            // ASCII string
  TCHAR szServerW[100];           // Unicode string
  TCHAR szError[100];             // Error message string
  WSADATA WSAData;                // Contains details of the
  PHOSTENT phostent = NULL;           // Points to the HOSTENT structure
 
                                  // Winsocket implementation
 
  // Initialize Winsocket.
  if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
  {
   wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
    WSAGetLastError ());
   MessageBox (NULL, szError, TEXT("Error"), MB_OK);
   return FALSE;
  }

  // Create a socket bound to the server.
  if ((ServerSock = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  {
    wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    return FALSE;
  }
  if ((phostent = gethostbyname (HOSTNAME)) == NULL)
  {
   wsprintf (szError, TEXT("Unable to get the host name. Error: %d"),
    WSAGetLastError ());
   MessageBox (NULL, szError, TEXT("Error"), MB_OK);
   closesocket (ServerSock);
   return FALSE;
  }
  server_sin.sin_family = AF_INET;
  // Assign the socket IP address.
  memcpy ((char FAR *)&(server_sin.sin_addr),
   phostent->h_addr,
   phostent->h_length);
 
  // Convert to network ordering.
  server_sin.sin_port = htons (PORTNUM);     
  // Associate the server socket address with the server socket.
  if (bind (ServerSock, (struct sockaddr *)&server_sin, sizeof (server_sin))
           == SOCKET_ERROR)
  {
    wsprintf (szError, TEXT("Binding socket failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    closesocket (ServerSock);
    return FALSE;
  }

  // Establish a socket to listen for incoming connections.
  if (listen (ServerSock, 5) == SOCKET_ERROR)
  {
    wsprintf (szError,
              TEXT("Listening to the client failed. Error: %d"),
              WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    closesocket (ServerSock);
    return FALSE;
  }

  // Accept a connection on the socket.
  if ((ClientSock = accept (ServerSock, 0, 0)) == INVALID_SOCKET)
  {
    wsprintf (szError, TEXT("Accepting connection with client failed.")
              TEXT(" Error: %d"), WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Error"), MB_OK);
    closesocket (ServerSock);
    return FALSE;
  }

  // Stop listening for connections from clients.
  closesocket (ServerSock);

  // Receive data from the client.
  iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);

  // Check if there is any data received. If there is, display it.
  if (iReturn == SOCKET_ERROR)
  {
    wsprintf (szError, TEXT("No data is received, recv failed.")
              TEXT(" Error: %d"), WSAGetLastError ());
    MessageBox (NULL, szError, TEXT("Server"), MB_OK);
  }
  else if (iReturn == 0)
  {
    MessageBox (NULL, szServerA, TEXT("Received Data"),
                MB_OK);
  }
  else
  {
    // Convert the ASCII string to a Unicode string.
    for (index = 0; index <= strlen (szServerA); index++)
      szServerW[index] = szServerA[index];

    // Display the string received from the client.
    MessageBox (NULL, szServerW, TEXT("Received From Client"), MB_OK);
  }
  TCHAR szReply[200] = "hello, ";
  strcat(szReply, szServerA);
  // Send a string from the server socket to the client socket.
 
  if (send (ClientSock, szReply, strlen (szReply) + 1, 0)
   == SOCKET_ERROR)
  {
   wsprintf (szError,
    TEXT("Sending data to the client failed. Error: %d"),
    WSAGetLastError ());
   MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  }
 
  // Close the client and server sockets.
  closesocket (ClientSock);

  return 0;
}


 

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值