PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

C语言基础(21)_socket编程(2)

接着上次的学习。上次尝试了TCP模式的网络通信,今天尝试UDP模式的对讲机模式网络通信。同样分为服务端和客户端。用的是WINDOWS平台下的SOCKET。

 

TCP与UDP区别:

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接;

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付;

3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的;UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等);

4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信;

5、TCP首部开销20字节;UDP的首部开销小,只有8个字节;

6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

 

从代码角度来说:

socket的类型,SOCK_STREAM(TCP)、SOCK_DGRAM(UDP);

TCP的服务端需要listen(); accept(); 客户端需要connect(); 而UDP则没有这些。

因为UDP没有显式的连接过程,所以必须是客户端首先发送数据。

 

一些用到的结构体和函数:

struct sockaddr_in

{

short   sin_family;

u_short sin_port;

struct  in_addr sin_addr;

char    sin_zero[8];

};

struct in_addr

{

union {

struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;

struct { u_short s_w1,s_w2; } S_un_w;

u_long S_addr;

} S_un;

#define s_addr  S_un.S_addr

/* can be used for most tcp & ip code */

#define s_host  S_un.S_un_b.s_b2

/* host on imp */

#define s_net   S_un.S_un_b.s_b1

/* network */

#define s_imp   S_un.S_un_w.s_w2

/* imp */

#define s_impno S_un.S_un_b.s_b4

/* imp # */

#define s_lh    S_un.S_un_b.s_b3

/* logical host */

};

 

unsigned long inet_addr ( const char FAR * cp ); //字符串地址转换为 unsigned long

char FAR * inet_ntoa (  struct in_addr in  ); //结构体转字符串地址

UDP服务端代码:

//UDP_SERVER_对讲机.cpp
//UDP 服务端 对讲机模式

#define WIN32_LEAN_AND_MEAN //这个可以解决 winsock2.h 写在 windows.h下面的错误,MSDN上copy
#define _WINSOCK_DEPRECATED_NO_WARNINGS //解决inet_addr("ip")的警告
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") //库文件

int main() {
 //一、版本协商(windows特有)
 WORD wVersionRequested; //WORD 是unsigned short类型
 WSADATA wsaData;
 wVersionRequested = MAKEWORD(2, 2); //版本2.2
 int err = WSAStartup(wVersionRequested, &wsaData); //返回0正确
 if (err != 0) {
 printf("WSAStartup Error!\n");
 return -1;
 }
 else 
 printf("WASStartup Successed!\n");
 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
 printf("对应版本的Winsock.dll没有找到。\n");
 WSACleanup();
 return -1;
 }
 else
 printf("Winsock 2.2 DLL OK!\n");
 //二、创建套接字
 SOCKET sockSer;
 sockSer = socket(AF_INET, SOCK_DGRAM, 0); //UDP类型

 //三、绑定套接字
 SOCKADDR_IN addrSer; //服务端地址信息
 addrSer.sin_family = AF_INET;
 addrSer.sin_port = htons(5050);
 addrSer.sin_addr.S_un.S_addr = INADDR_ANY; //可以写 inet_addr("127.0.0.1") ip
 bind(sockSer, (SOCKADDR*)&addrSer, sizeof(SOCKADDR));

 //四、接收和发送
 char sendbuf[256]; //发送缓冲区
 char recvbuf[256]; //接收缓冲区
 SOCKADDR_IN addrCli; //客户端地址信息
 int len = sizeof(SOCKADDR);
 printf("Waiting Client...\n");
 while (1) {
 printf("Cli:>");
 recvfrom(sockSer, recvbuf, 256, 0, (SOCKADDR*)&addrCli, &len);
 printf("%s\n", recvbuf);
 printf("Ser:>");
 gets_s(sendbuf, 256);
 if (strcmp(sendbuf, "quit") == 0) break;
 sendto(sockSer, sendbuf, sizeof(sendbuf) + 1, 0, (SOCKADDR*)&addrCli, len);
 }

 //五、关闭套接字
 closesocket(sockSer);
 WSACleanup();

 return 0;
}

UDP客户端代码:

//UDP_CLIENT_对讲机.cpp
//UDP 客户端 对讲机模式
#define WIN32_LEAN_AND_MEAN //这个可以解决 winsock2.h 写在 windows.h下面的错误,MSDN上copy
#define _WINSOCK_DEPRECATED_NO_WARNINGS //解决inet_addr("ip")的警告
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") //库文件

int main() {
 //一、版本协商(windows特有)
 WORD wVersionRequested;
 WSAData wsaData;
 wVersionRequested = MAKEWORD(2, 2);
 int err = WSAStartup(wVersionRequested, &wsaData); //返回0正确
 if (err != 0) {
 printf("WSAStartup Error!\n");
 return -1;
 }
 else
 printf("WSAStartup Successed!\n");
 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
 printf("对应版本的Winsock.dll没有找到。\n");
 WSACleanup();
 return -1;
 }
 else 
 printf("Winsock 2.2 DLL OK!\n");

 //二、创建套接字
 SOCKET sockCli;
 sockCli = socket(AF_INET, SOCK_DGRAM, 0);//以UDP方式

 SOCKADDR_IN addrSer;
 addrSer.sin_family = AF_INET;
 addrSer.sin_port = htons(5050);
 addrSer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

 //三、发送接收数据
 char sendbuf[256];
 char recvbuf[256];
 int len = sizeof(SOCKADDR);
 while (1) {
 printf("Cli:>");
 gets_s(sendbuf, 256);
 if (strcmp(sendbuf, "quit") == 0) break;
 sendto(sockCli, sendbuf, sizeof(sendbuf) + 1, 0, (SOCKADDR*)&addrSer, sizeof(SOCKADDR));
 printf("Ser:>");
 recvfrom(sockCli, recvbuf, 256, 0, (SOCKADDR*)&addrSer, &len);
 printf("%s\n", recvbuf);
 }

 //四、关闭套接字
 closesocket(sockCli);
 WSACleanup();
 return 0;
}

(2017-03-26 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » C语言基础(21)_socket编程(2)

分享到:更多 ()

评论 77

评论前必须登录!