Winsock 初探II 简单TCP/IP 和UDP/IP 程序

前些天写了Winsock 初探一文,现在继续往下写。本文的目的不是想介绍一个完整的网络应用程序,而只是作为一个初步介绍如何写一个网络程序,正因为是初探,所以代码比较简单,为了使代码清晰起见,我省略了错误检查代码部分,但这不意味着错误检查不重要。

写一个网络应用程序分为两个方面:服务器程序和客户端程序,大家可以在一个solution中建立srv和client两个projects。

首先回忆一下程序框架,见Winsock 初探 一文

  1. #include<winsock2.h>   // 头文件
  2. #pragma comment(lib, "ws2_32.lib") // 库文件加载
  3. void main(void)
  4. {
  5.     WSADATA wsaData;  // WSADATA 结构体主要包含了系统所支持的Winsock版本信息          
  6.     
  7.    // 初始化Winsock 2.2。使用WSAStartup函数,第一个参数是所要用的Winsock版本号
  8.    // 第二个参数就是WSADATA结构体的指针。如果初始化成功则返回0
  9.    // 要注意任何WinsockAPI函数都必须在初始化后使用,包括错误检查函数
  10.    // WSAGetLastError (用于查看出错详细信息)
  11.    if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 )
  12.     {
  13.        printf( "WSAStartup 无法初始化!");
  14.       return;
  15.     }  
  16.     // winsock 应用代码
  17.     // 最后应该做一些清除工作
  18.     if( WSACleanup() == SOCKET_ERROR )
  19.          printf( "WSACleanup 出错!");
  20. }

现在我们的任务是填写红色的部分,即winsock应用代码

1. 简单TCP/IP

思路:

[服务器程序]

建立socket -----> 绑定bind------>监听listen------>接受accept------>发送和接收send 和 recv------>关闭closesocket

[客户端程序]

建立socket -----> 连接connect------>发送和接收send 和 recv------>关闭closesocket

代码:

[服务器程序]

  1. /*使用IP地址家族就必须要用AF_INET,由于我们要建立可靠的传送,因此我们选择SOCK_STREAM,基于数据流的传送,最后一个参数表示使用TCP协议,实际上这个参数可以设置为0,让程序自己根据情况判断填写*/
  2. SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )
  3. /*绑定的意思是把socket绑定到IP地址上,所以我们需要一个SOCKADDR结构来存放IP地址信息,这里为了方便填写可以使用SOCKADDR_IN结构,这个结构的大小和SOCKADDR一样,可以强制类型转换到SOCKADDR类型,填写给bind函数的参数。这里要注意的是要把IP地址和端口号转化为网络存储顺序,即高位存放在低字节内存中,可以用htonl和htons函数转化*/
  4. SOCKADDR_IN addrSrv;
  5. addrSrv.sin_family = AF_INET;
  6. addrSrv.sin_addr.s_addr = htonl( INADDR_ANY);  // INADR_ANY表示使用默认IP地址
  7. addrSrv.sin_port = htons( 27015 );//尽量不要使用在1024以下的端口
  8. bind( sockSrv, (SOCKADDR*)&addrSrv, sizeof(addrSrv) );
  9. /*/ 监听,第二个参数表示等待序列的最大个数,就好比最多只能容纳5个人排队,第六个就被拒绝排队了。*/
  10. listen( sockSrv, 5 );
  11. /* 接受, 就好比处理房间中第一个人的事务,那么这个队列就空出一个人的位置,其他人还可以来排队。这里通过accept函数可以返回一个表示连接进来的客户的socket,并且通过传递参数可以知道客户端的IP地址信息*/
  12. SOCKADDR_IN addrClient;
  13. int len = sizeof(addrClient);
  14. // 循环接受客户,这里没有写退出条件,实际上退出条件可以来自判断所读入的信息
  15. while(1)
  16. {
  17.     SOCKET sockClient = accept( sockSrv, (SOCKADDR*)&adrClient, &len );
  18.    // 发送和接收数据
  19.     char sendbuf[32] = "Server: Sending Data.";
  20.     char recvbuf[32] = "";
  21.   
  22.     // recv 和 send的参数都是 socket,buffer,buffer的大小以及一个flag,具体可参考MSDN
  23.      bytesRecv = recv( sockClient, recvbuf, 32, 0 );
  24.      printf( "Recv: %s/n", recvbuf );
  25.     
  26.      bytesSent = send( sockClient, sendbuf, strlen(sendbuf), 0 );
  27. }
  28. // 关闭socket
  29. closesocket(sockClient);
  30. closesocket(sockSrv);

[客户端程序]

  1. SOCKET sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )
  2. SOCKADDR_IN addrSrv;
  3. addrSrv.sin_family = AF_INET;
  4. addrSrv.sin_addr.s_addr = htonl( INADDR_ANY);  // INADR_ANY表示使用默认IP地址
  5. addrSrv.sin_port = htons( 27015 );//尽量不要使用在1024以下的端口
  6. // 连接
  7. connect( sockSrv, (SOCKADDR*)&addrSrv, sizeof(addrSrv) );
  8.    // 发送和接收数据
  9.     char sendbuf[32] = "Client: Sending Data.";
  10.     char recvbuf[32] = "";
  11.   
  12.     // recv 和 send的参数都是 socket,buffer,buffer的大小以及一个flag,具体可参考MSDN
  13.      bytesRecv = recv( sockClient, recvbuf, 32, 0 );
  14.      printf( "Recv: %s/n", recv);
  15.     
  16.      bytesSent = send( sockClient, sendbuf, strlen(sendbuf), 0 );
  17. // 关闭socket
  18. closesocket(sockClient);

2. 简单UDP/IP

思路:

[服务器程序]

建立socket -----> 绑定bind------>发送和接收sendto 和 recvfrom------>关闭closesocket

[客户端程序]

建立socket -----> 发送和接收send 和 recv------>关闭closesocket

UDP的实现更加简单,服务器只要绑定就可以发送接收信息,而客户端只要有socket就可以了。具体的实现代码可以参考MSDN中的例子。

要注意的是:

TCP中用SOCK_STREAM 建立socket,并且使用send和recv函数发送接收信息。

UDP中用SOCK_DGRAM 建立socket,并且使用sendto和recvfrom来发送和接收信息。sendto 比send多几个参数,主要是对方的IP地址信息,recvfrom也是一样比recv多几个参数。

以上所讨论的仅仅是为了显示一下编写网络应用程序基本思路,至于具体实际的代码还是要看看具体的源代码,如果要使用图形界面则所要用的函数和类会更加多。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值