原文链接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html

1.基于 TCP 的 socket 编程

/*
服务器端程序流程:
1.加载套接字库 WSAStartup
2.创建套接字 socket
3.将我们创建的套接字,绑定到本机地址的某一端口上 bind
4.为套接字设置监听模式,准备客户请求 listen
5.等待客户请求到来。当请求到来,将接受连接请求,并返回一个新的对应于此次连接的套接字 accept
6.用新返回的套接字和客户端进行通信 send / recv
7.在通信结束后,关闭套接字 closesocket 客户端程序流程:
1.加载套接字库 WSAStartup
2.创建套接字 socket
3.向服务器发出请求连接 connect
4.和服务器进行通信 send / recv
5.在通信结束后,关闭套接字 closesocket
*/

服务器端代码:

#include <Winsock2.h>
#include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main()
{
// 加载套接字库,并进行套接字的版本协商
WORD wVersionRequested; // 指定将要加载的 winsock 库版本
WSADATA wsaData; // 用于存储加载的 winsock 库版本信息
int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0
// 出错处理
if (result != 0)
{
return;
} if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
} // 创建套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // 绑定套接字
SOCKADDR_IN addrInfo; // 存储本地主机地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主机地址
addrInfo.sin_port = htons(6000); // 端口号
addrInfo.sin_family = AF_INET; // 地址族 bind(sock, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 设置套接字监听模式
listen(sock, 5); SOCKADDR_IN addrInfoClient; // 存储客户端地址信息
int len = sizeof(SOCKADDR); while (true)
{
// 等待客户请求到来,并返回用于通信的套接字
SOCKET sockConnect = accept(sock, (SOCKADDR *)&addrInfoClient, &len); // 下面通过刚建立的套接字,来进行通信 // 发送数据
char sendBuf[100];
sprintf(sendBuf, "这是服务器端,主机地址:%s", inet_ntoa(addrInfo.sin_addr));
send(sockConnect, sendBuf, strlen(sendBuf), 0); // 接收数据
char recvBuf[100];
recv(sockConnect, recvBuf, strlen(recvBuf), 0); // 打印接收的数据
printf("%s\n", recvBuf); closesocket(sockConnect);
} }

客户端代码:

#include <Winsock2.h>
#include <stdio.h> #pragma comment(lib,"Ws2_32.lib") void main()
{
// 加载套接字库,并进行套接字的版本协商
WORD wVersionRequested; // 指定将要加载的 winsock 库版本
WSADATA wsaData; // 用于存储加载的 winsock 库版本信息
int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0
// 出错处理
if (result != 0)
{
return;
} if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
} // 创建套接字
SOCKET sockConnect = socket(AF_INET, SOCK_STREAM, 0); // 向服务器发出连接请求
SOCKADDR_IN addrInfoServer; // 存储服务器端地址信息
addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrInfoServer.sin_port = htons(6000);
addrInfoServer.sin_family = AF_INET; // 向服务器发出连接请求
connect(sockConnect, (SOCKADDR *)&addrInfoServer, sizeof(SOCKADDR)); // 接收数据
char recvBuf[100];
recv(sockConnect, recvBuf, sizeof(recvBuf), 0);
printf("%s\n", recvBuf); // 发送数据
char sendBuf[100] = "这是客户端\n";
send(sockConnect, sendBuf, sizeof(sendBuf) + 1, 0); //关闭套接字
closesocket(sockConnect); WSACleanup(); system("pause");
return;
}

2. 基于 UDP 无连接的 socket 编程

/*

服务端程序流程:
1.加载套接字库 WSAStartup
2.创建套接字 socket
3.将创建的套接字绑定到一个本地地址和端口上 bind
4.等待接收数据。后与客户端实现实时交流 recvfrom / sendto
5.关闭套接字 closesocket 客户端程序流程:
1.加载套接字库 WSAStartup
2.创建套接字 socket
3.向服务器发送数据.后与服务端实现实时交流 recvfrom / sendto
4.关闭套接字 closesocket */

服务器端代码:

#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib") void main()
{
// 加载套接字库,并进行套接字的版本协商
WORD wVersionRequested; // 指定将要加载的 winsock 库版本
WSADATA wsaData; // 用于存储加载的 wdnsock 库版本信息
int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0
// 出错处理
if (result != 0)
{
return;
} if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
} // 创建用于套接字
SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 绑定套接字
SOCKADDR_IN addrInfo; // 存储本地主机地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主机地址
addrInfo.sin_port = htons(6000); // 端口号
addrInfo.sin_family = AF_INET; // 地址族 bind(sockConnect, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 等待接收数据
char recvBuf[100]; // 接收数据缓冲
char sendBuf[100]; // 发送数据缓冲
char tempBuf[200]; SOCKADDR_IN addrInfoClient; // 存储客户端地址信息
int len = sizeof(SOCKADDR); while (true)
{
recvfrom(sockConnect, recvBuf, strlen(recvBuf), 0, (SOCKADDR *)&addrInfoClient, &len);
if ('q' == recvBuf[0])
{
sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrInfoClient, len);
printf("聊天结束");
break;
} sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoClient.sin_addr), recvBuf);
printf("%s\n", tempBuf); // 发送数据
printf("我说:");
gets(sendBuf);
sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrInfoClient, len);
} // 关闭套接字
closesocket(sockConnect);
WSACleanup(); }

客户端代码:

#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib") void main()
{
// 加载套接字库,并进行套接字的版本协商
WORD wVersionRequested; // 指定将要加载的 winsock 库版本
WSADATA wsaData; // 用于存储加载的 wdnsock 库版本信息
int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0
// 出错处理
if (result != 0)
{
return;
} if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
} // 创建套接字
SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 向服务器发送数据
SOCKADDR_IN addrInfoServer; // 存储服务器地址信息 addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 指定服务器地址
addrInfoServer.sin_port = htons(6000); // 端口号
addrInfoServer.sin_family = AF_INET; // 地址族 int len = sizeof(SOCKADDR); char recvBuf[100]; // 接收数据缓冲
char sendBuf[100]; // 发送数据缓冲
char tempBuf[200]; while (true)
{
// 发送数据
printf("我说:");
gets(sendBuf);
sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrInfoServer, len); // 等待并接收数据
recvfrom(sockConnect,recvBuf, strlen(recvBuf), 0, (SOCKADDR*)&addrInfoServer, &len);
if ('q' == recvBuf[0])
{
sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrInfoServer, len);
printf("聊天结束");
break;
} sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoServer.sin_addr), recvBuf);
printf("%s\n", tempBuf);
} // 关闭套接字
closesocket(sockConnect);
WSACleanup(); }

3.其他

vc网络编程常用类型解析:  

1. SOCKET 类型
SOCKET 是 socket 套接字类型,在 WINSOCK2.H 中有如下定义:
typedef unsigned u_int;
typedef u_int SOCKET;
可知套接字实际上就是一个无符号整形,它将被 Socket 环境管理和使用。
套接字将被创建、设置、用来发送和接收数据,最后会被关闭。 2.WORD 类型、MAKEWORD、LOBYTE、HIBYTE 宏
WORD 类型是一个 16 位的无符号整型, 在 WTYPES.H 中被定义为:
typedef unsigned short WORD;
其目的是提供两个字节的存储, 在 Socket 中这两个字节可以表示主版本号和副版本号。
使用 MAKEWORD 宏可以给一个 WORD 类型赋值。例如要表示主版本号 2, 副版本号 0,可以使用如下代码:
WORD wVersionRequested;
wVersionRequested = MAKEWORD(2, 0);
注意低位内存存储主版本号 2, 高位内存存储副版本号 0,其值为 0x0002。
使用宏 LOBYTE 可以读取 WORD 的低位字节, HIBYTE 可以读取高位字节。 3.WSADATA 类型和 LPWSADATA 类型
WSADATA 类型是一个结构,描述了 Socket 库的一些相关信息,其结构定义如下: typedef struct WSAData
{
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN + 1];
char szSystemStatus[WSASYS_STATUS_LEN + 1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR* lpVendorInfo;
}WSADATA;
typedef WSADATA FAR* LPWSADATA; 值得注意的是 wVersion 字段,存储了 Socket 的版本类型。LPWSADATA 是 WSADATA 的指针类型。
他们通过 Socket 的初始化函数 WSAStartup 读取出来。 //////////////////////////////////////////////////////////////////////////////////////// vc网络编程常用函数解析: 1. WSAStartup 函数
用于初始化 Socket 环境,函数原型:
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
其返回值为整型,调用方式为 PASCAL (即标准类型,PASCAL 等于__stdcall),参数有两个,
第一个参数为 WORD 类型,指明了 Socket 的版本号,第二个参数为 LPWSADATA,指向一个用于存储 Socket 库信息的WSAStartup结构。
返回值:
返回值为0,则初始化成功,若不为0则为失败。 2.WSACleanup 函数
这是 Socket 环境的退出函数,函数原型:
int WSACleanup (void);
返回值:
返回值为0表示成功,SOCKET_ERROR 表示失败。 3.socket 函数
socket 套接字的创建函数,函数原型:
SOCKET socket(int af, int type, int protocol );
第一个参数为:int af, 代表网络地址族,目前只有一种取值有效,即 AF_INET, 代表 internet 地址族;
第二个参数为:int type, 代表网络协议类型, SOCK_DGRAM 代表 UDP 协议, SOCK_STREAM 代表 TCP 协议。
第三个参数为:int protocol,指定网络地址族特殊协议,目前无用,赋值0即可。
返回值:
返回值为 SOCKET, 若返回INVALID_SOCKET 则失败。 4.bind 函数
用于将套接字绑定到一个已知地址上,函数原型:
int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);
第一个参数为:SOCKET s, 指定将被绑定的套接字。
第二个参数为:SOCKADDR_IN *name, 是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口。
第三个参数为:int namelen, 确定第二个参数的结构长度。 返回值: 成功返回0,失败返回SOCKET_ERROR。 /////////////////////////////////////////////////////////////////////////////////////////////////// 下面对其涉及的类型作一番解析:
sockaddr 类型:
sockaddr 类型是用来表示 Socket 地址的类型,同上面的 socketaddr_in 类型相比,sockaddr 的适用范围更广,
因为sockeaddr_in只适用于 TCP/IP 地址。sockaddr 的定义如下:
struct sockaddr
{
ushort sa_family;
char sa_data[14];
};
可知sockaddr 的16个字节,而sockaddr_in也有16个字节,所以sockaddr_in是可以强制类型转换为sockadddr的。
事实上也往往使用这种方法。 sockaddr_in 定义了socket发送和接收数据包的地址,其定义如下:
strucr sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}; 其中 in_addr 定义如下:
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;
};
首先阐述 in_addr 的信义。
很显然它是一个存储 ip 地址的联合体,有三种表达方式:
第一种用四个字节来表示IP地址的四个数字;
第二种用两个双字节来表示IP地址;
第三种用一个长整型来表示IP地址;
给 in_addr 赋值的一种最简单方法是使用 inet_addr 函数, 它可以把一个代表IP地址的字符串赋值
转换为in_addr类型。如:
addrServer.sin_addr = inet_addr("192.168.0.2");
其反函数是 inet_ntoa,可以把一个 in_addr 类型转换为一个字符串。
sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下:
第一字段 short sin_family,代表网络地址族,如前所述,只能取值AF_INET;
第二字段 u_short sin_port, 代表IP地址端口,由程序员指定;
第三字段 struct in_addr sin_addr, 代表IP地址;
第四个字段char sin_zero[8],是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。 5.listen 函数
该函数让一个套接字在指定IP地址的指定端口处监听连接请求的到来,函数原型:
int listen( SOCKET s, int backlog );
该函数使得一个进程可以接受其他进程的请求,从而成为一个服务器进程。
在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
listen 函数一般在调用bind之后、调用accept之前调用。
返回值: 成功则返回0,失败返回SOCKET_ERROR,可以调用函数WSAGetLastError来取得错误代码。 6.accept函数
该函数从连接请求队列中获得连接信息,并创建新的套接字用于收发数据,实现服务器与客户端的通信。函数原型:
SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
第一个参数:SOCKET s, 监听套接字
第二个参数:struct sockaddr addr, 存储请求连接的客户端IP地址、端口信息
第三个参数:int addrlen,第二个参数所占空间大小
返回值:
成功返回新套接字,失败返回错误信息 7.connect 函数
向指定的网络主机请求连接,函数原型:
int connect(SOCKET s, const struct sockaddr FAR *name, int namelen);
第一个参数:SOCKET s, 客户端用于收发数据的套接字。
第二个参数:struct sockaddr *name, 指定网络主机IP地址和端口号。
第三个参数:int namelen, 第二参数长度
返回值:
成功返回0,失败返回-1。 8.sendto、recvfrom、send、recv函数
在 Socket 中有两套发送和接收函数。一是sendto 和recvfrom; 二是send 和 recv。
前一套在函数参数中要指明地址(UDP协议),
而后一套需要先将套接字和一个地址绑定,然后直接发送和接收,不需绑定地址。
函数原型:
int sendto( SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to, int tolen);
int recvfrom(SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen); int send(SOCKET s,const char FAR *buf, int len, int flags);
int recv(SOCKET s, char FAR *buf, int len, int flags); 第一个参数: 套接字
第二个参数: 数据指针
第三个参数: 数据长度
第四个参数: 收发数据方式的标识,如果不需要特殊要求可以设置为0,其他值可参考MSDN;
第五个参数: 目标主机地址
第六个参数: 地址的长度 返回值: 运行成功则返回收发数据的字节数,失败返回SOCKET_ERROR 9.closesocket 函数
关闭套接字,函数原型:
int closesocket( SOCKET s );
返回值: 成功返回0,失败返回SOCKET_ERROR。

MFC 网络编程 -- 总结的更多相关文章

  1. 转:MFC网络编程学习

    要学习好网路编程,主要看以下几个方面: 1.掌握概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)等. 2.在实际Windows网络通信软件开发中,异步非阻 ...

  2. 《转》MFC网络编程学习

    原地址:http://www.cnblogs.com/renyuan/archive/2013/06/04/3117006.html要学习好网路编程,主要看以下几个方面: 1.掌握概念,诸如:同步(S ...

  3. MFC 网络编程中::connect返回-1问题

    在MFC编写网络时遇到了::connect总是返回-1,但是与服务器可以进行接收和发送消息的操作. 原因是在进行连接的时候我没有进行初始化:::WSAStartup(w, &data);//动 ...

  4. MFC网络编程

    一.概念1.同步方式与异步方式同步方式:发送方不等接收方响应,便接着发送下一个数据包的通信方式异步方式:发送方发出数据,等收到接收方发回的响应后,才发送下一个数据包的通信方式2.阻塞与非阻塞方式阻塞套 ...

  5. CSocket类网络编程 MFC

    Visual C++的MFC提供了CSocket类用来实现网络通信. 下面介绍VC++在Windows 95中实现Socket的 CSocket 类相关成员函数(这些成员函数实际上是从CAsyncSo ...

  6. VC++ 网络编程总结(一)

    1.套接字编程原理         一个完整的网间通信进程需要由两个进程组成,并且只能用同一种高层协议.也就是说,不可能通信的一段用TCP,而另一端用UDP.一个完整的网络信息需要一个五元组来标识:协 ...

  7. 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三

       手把手叫你玩转网络编程系列之三    完毕port(Completion Port)具体解释                                                    ...

  8. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  9. C#网络程序设计(1)网络编程常识与C#常用特性

        网络程序设计能够帮我们了解联网应用的底层通信原理!     (1)网络编程常识: 1)什么是网络编程 只有主要实现进程(线程)相互通信和基本的网络应用原理性(协议)功能的程序,才能算是真正的网 ...

随机推荐

  1. 2013/11/22工作随笔-缓存是放在Model层还是放在Controller层

    web网站的典型代码框架就是MVC架构,Model层负责数据获取,Controller层负责逻辑控制,View层则负责展示. 一般数据获取是去mysql中获取数据 但是这里有个问题,我们不会每次请求都 ...

  2. (8)分布式下的爬虫Scrapy应该如何做-图片下载(源码放送)

      转载主注明出处:http://www.cnblogs.com/codefish/p/4968260.html 在爬虫中,我们遇到比较多需求就是文件下载以及图片下载,在其它的语言或者框架中,我们可能 ...

  3. 订餐App回顾与总结

    MY-HR 成员: 角色分配 学号 博客园 丘惠敏 PM项目经理 201406114203 http://www.cnblogs.com/qiuhuimin/ 郭明茵 用户 201406114204 ...

  4. ok6410 android driver(7)

    This article talk about how to test device driver on JNI. There are two ways to test the device driv ...

  5. 给文本框添加模糊搜索功能(“我记录”MVC框架下实现)

    步骤: 1.在文本框中输入内容时,触发keyup事件: 2.在keyup事件的处理方法中,通过Ajax调用控制器的方法: 3.在控制器方法中,搜索满足条件的数据,这里分页获取数据,且只取第一页的数据, ...

  6. 随笔分类 - 无废话ExtJs系列教程

    随笔分类 - 无废话ExtJs系列教程 摘自:http://www.cnblogs.com/iamlilinfeng/category/385121.html ExtJs 入门教程 摘要: extjs ...

  7. Ajax学习资源大全[本来是转载的,但是现在我增加了很多]

    本欲放转载区,但是这样一文章放那里基本是没有用的,帮助不了任何人!所以放新手了!! 我一般非经典或者自己用不上不转载,所以如果你不幸看见了的话,恰恰你又对AJAX有兴趣的话不防看下,也许对你有用的!! ...

  8. JSONArray.toCollection 封装 bean 失败

    1. 问题描述: 通过http请求服务端, 返回的bean的集合的字符串形式, 其中bean中的Date类型的属性值,形式为Long类型的表示形式(1466083519000): String res ...

  9. T-SQL的回车和换行符(SQL)

    T-SQL的回车和换行符(SQL) sql server中的回车换行字符是  char(13)+char(10) 回车:char(13) 换行:char(10) 实例1: DECLARE @c NVA ...

  10. ahjesus linux连接阿里云ubuntu服务器并更改默认账号和密码,以及创建子账户

    先确保本地Linux服务器SSH服务开启,如果没有开启直接执行指令:service sshd start 然后我们使用ssh指令进行远程登陆 ssh username@ip-address 输入pas ...