windows网络编程【003】实现简单WSASocket的C/S结构

    运行时,请先启动服务器端。

/*
* 服务器端
*/


#include   
< Winsock2.h >    
#include   
< stdio.h >    
#include   
< iostream.h >  
#pragma comment(lib,
" Ws2_32.lib " )  
     
SOCKET   sockSvc;
// 服务器端socket
SOCKET   sockConnect;    // 连接用的socket
    
DWORD WINAPI RecvData(LPVOID   lpParameter);  
// 接收线程的函数 
    
int  main()   
{   
  WORD   wVersionRequested;
//定义socket1.1或者socket2.0   
  WSADATA   wsaData;   //定义装载socket版本的变量
  int   err;   //错误变量
    
  wVersionRequested 
= MAKEWORD(2,2);   //定义连接为socket2.0
    
  err  
=  WSAStartup(wVersionRequested, &wsaData);   //装载socket2.0支持
  if(0 != err)//判断是否装载成功
  {   
    
return -1;   
  }
   

  
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)//判断版本号,是否和定义的一样
  {   
     WSACleanup();   
//若出问题,卸载支持,并结束程序返回-1
     return -1;     
  }
   
    
  sockSvc 
= WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
  
/*
  
    SOCKET WSASocket(int af, int type, int protocol,
                 LPWSAPROTOCOL_INFO lpprotocolinfo,
                 GROUP g, DWORD dwflags)

    SOCKET socket(int af, int type, int protocol)
    参数:地址族,套接字类型和协议类型
          这三个因素共同决定了创建套接字的服务提供者
    
    传输服务提供者实现的功能包括建立连接,传输数据,实现流控制和差错控制等函数。
    Ws2_32.dll在应用程序和服务提供者之间实现了媒介的功能

 
  第一
      socket()和WSASocket()函数都能返回一个SOCKET套接字;
      socket()主要实现同步传输,Socket库中例程在应用于阻塞套接口时会阻塞。
      WSASocket()用于异步传输,WSASocket()的发送操作和接收操作都可以被重叠使用。
      
      WSASocket()的接收函数可以被多次调用,发出接收缓冲区,准备接收到来的数据。
                 发送函数也可以被多次调用,组成一个发送缓冲区队列。
      socket()却只能发过之后等待回消息才可做下一步操作!
  其次    
      WSASocket()所支持的版本如下:   
                        Version:   Requires   Windows   Sockets2.0.   
                        Header:   Declared   in   Winsock2.h.   
      socket()所支持老一些的版本,如Windows   Sockets1.0和   
                        Version:   Requires Windows   Sockets1.1
  
*/

    
  SOCKADDR_IN  addrSvc; 
//服务器地址信息 
  addrSvc.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //0 接收所有数据包  
  addrSvc.sin_family   =  AF_INET;   
  addrSvc.sin_port  
=  htons(4000);//监听 端口
    
  bind(sockSvc,(SOCKADDR
*)&addrSvc,sizeof(SOCKADDR)); //绑定服务和端口  
    
  listen(sockSvc,
50);   
  
/*
    int listen(SOCKET s, int users); 
    服务程序可以调用listen函数使其流套接字s处于监听状态。处于监听状态的流套接字s将维
    护一个客户连接请求队列,该队列最多容纳users个客户连接请求。假如该函数执行成功,
    则返回0;如果执行失败,则返回SOCKET_ERROR。
  
*/

    
  SOCKADDR_IN   addrClient;   
  
int length = sizeof(SOCKADDR);   
    
  
while(1)   
  
{   
  sockConnect 
= accept(sockSvc, (SOCKADDR*)&addrClient,&length); 
  
/*
   SOCKET accept( 
      SOCKET s, 
      struct sockaddr FAR *addr, 
      int FAR *addrlen 
   ); 
   服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,
   并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,
   以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数
   指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用
   第三个参数来返回新创建的套接字的地址结构的长度。
  
*/

  
if(INVALID_SOCKET != sockConnect)   
  
{   
      HANDLE   hThread;   
      hThread
=CreateThread(NULL,0,RecvData,(LPVOID)sockConnect,0,NULL); 
      
/*
      /*
      我们得定义一个句柄用来存放它的返回值。还定义一个指向线程ID的DWORD值dwThreadId。
        CreateThread函数有六个参数分别是
         LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes
         DWORD dwStackSize,                         // initial thread stack size
         LPTHREAD_START_ROUTINE lpStartAddress,     // pointer to thread function
         LPVOID lpParameter,                        //argument for new thread
         DWORD dwCreationFlags,                     // creation flags
         LPDWORD lpThreadId                         // pointer to receive thread ID
      中第一个参数我们设置为NULL,使这个句柄不能被继承;第二个参数设置为0,使用默认的堆栈
      大小;第三个参数为线程函数的起始地址,也就是线程函数的函数名;第四个参数要传递给线程
      函数的值;第五个参数为0,创建好之后马上让线程运行;第六个参数设置为指向线程ID的地址。
      严格来说这里需要加错误检测if(NULL == hThead){}
      
*/

      CloseHandle(hThread);   
  }
   
  }
   
    
  Sleep(INFINITE);   
  closesocket(sockConnect);   
  WSACleanup();  
// 严格来说这里需要加错误检测if(0 != WSACleanup()){}
  }
   
    
  DWORD   WINAPI   RecvData(LPVOID   lpParameter)  
// 线程接收函数  
   {   
  SOCKET   socket   
=   (unsigned  int)lpParameter;   
  
char   recvBuffer[1024];   
  
for(;;)   
  
{   
  
//receive   data   from   client   
  if(SOCKET_ERROR == recv(socket, recvBuffer, 10240)) //和客户端的send相对应  
  {   
     cout
<<"The   receive   data   defeat   or   was   the   client   side   already   withdraws\n"<<endl;   
     
break;   
  }
   
  cout
<<"Client says: "<<recvBuffer<<endl;   
  }
   
  closesocket(socket);   
// 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
  return  0;   
}
   


/*
* 客户端
*/


#include
< Winsock2.h >    
#include
< stdio.h >    
#pragma comment(lib,
" Ws2_32.lib " )

void  main()   
{   
  WORD   wVersionRequested;   
  WSADATA   wsaData;   
  
int   err;   
    
  wVersionRequested 
= MAKEWORD(22);   
    
  err 
= WSAStartup(wVersionRequested, &wsaData);   
  
if(err != 0){   
     
return;   
  }
   
    
    
  
if(LOBYTE(wsaData.wVersion) != 2 ||
     HIBYTE(wsaData.wVersion) 
!= 2 ){   
     
      WSACleanup();   
      
return;     
  }
   

  SOCKET sockClient 
= WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
  SOCKADDR_IN   addrClient;   
//服务器地址信息
  addrClient.sin_addr.S_un.S_addr = inet_addr("192.168.94.37");   //要连接的服务地址
  addrClient.sin_family = AF_INET; //协议族  
  addrClient.sin_port = htons(4000);  //请求的端口 
    
  
char  sendBuffer[1024];   //每次发送的最大数据量
  connect(sockClient, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));//连接服务器端   
  while(true)   
  
{   
    
/*send   data   to   service*/   
    printf(
"Please   input   data:\n");   
    
if(gets(sendBuffer) == NULL)  //输入要发送的数据 
    break;   
    
else   
    
{   
      
if(SOCKET_ERROR == send(sockClient,sendBuffer,
          strlen(sendBuffer)
+1,0)) //TCP方式发送  
      {   
         printf(
"Transmission data defeat!\n");   
         
break;   
      }
   
    }
   
  }
   
  closesocket(sockClient);    
// 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
  WSACleanup();   
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值