Windows网络编程 2 【转】
Windows网络编程使用winsock。Winsock是一个基于Socket模型的API,在Windows系统中广泛使用。
使用Winsock进行网络编程需要包含头文件Winsock2.h,需要使用库ws2_32.lib,包含方法:可以使用语句来告诉编译器连接该库
#pragma comment(lib, “ws2_32.lib”);
如果使用VS,可以通过“项目” --> “XX属性”--> “连接器”-->“输入”--> “附加依赖项”添加ws2_32.lib。 (XX为当前工程名)
● 面向连接的C/S程序工程流程图
使用Winsock API编制的网络应用程序中,在调用任何一个Winsock函数之前都必须检查协议栈安装情况,使用函数WSAStartup()完成操作。
● 一个服务端的例子

void server::startServer()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
//Winsock初始化错误
msgBox.exec();
return;
}
if(wsaData.wVersion!=wVersionRequested)
{
//Winsock版本不匹配
WSACleanup();
return;
} if ((m_sk = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
WSACleanup();
return;
}
bool ok;
unsigned short port = ui.portLineEdit->text().toInt(&ok, 10);
if (ok == false)
{
//端口输入错误
closesocket(m_sk);
m_sk = -1;
WSACleanup();
return;
} sockaddr_in addr;
addr.sin_family = AF_INET; //使用互联网际协议,即IP协议
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); if (bind(m_sk, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
{
//绑定端口失败 closesocket(m_sk);
m_sk = -1;
WSACleanup();
return;
} if (listen(m_sk, 10) == SOCKET_ERROR)
{
//监听端口失败
closesocket(m_sk);
m_sk = -1;
WSACleanup();
return;
}
updateMsgRecs(tr("等待连接..."));
//创建线程去等待连接
HANDLE h = CreateThread(NULL, 0, &server::acceptProc, (LPVOID)this, 0, 0);
if (h == NULL)
{
closesocket(m_sk);
m_sk = -1;
WSACleanup();
return;
}
CloseHandle(h);
}

● 监听线程函数

DWORD WINAPI server::acceptProc(LPVOID lpParamter)
{
/*server *p_server = (server *)lpParamter;
sockaddr_in client_addr;
int len = sizeof(client_addr);
char msgBuff[256];
int sk;
while (1)
{
if ((sk = ::accept(p_server->sk(), (sockaddr*)&client_addr, &len) )== SOCKET_ERROR)
{
emit p_server->haveNewMsg(QObject::tr("accept 出错"));
break;
} sprintf(msgBuff, "新连接来自%s", inet_ntoa(client_addr.sin_addr));
emit p_server->haveNewMsg(msgBuff);
emit p_server->newClient(inet_ntoa(client_addr.sin_addr), sk);
}*/ server *p_server = (server *)lpParamter;
int client[FD_SETSIZE];
fd_set allset, rset;
sockaddr_in client_addr;
int len;
int clientfd;
int sockfd; int i;
for (i=0; i<FD_SETSIZE; i++)
client[i] = -1;
FD_ZERO(&allset);
int listenfd = p_server->sk();
FD_SET(listenfd, &allset); int nready;
int maxfd = listenfd;
int maxi = -1;
char buff[MAX_LEN+1]; while (1)
{
rset = allset;
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &rset)) //new connection
{
len = sizeof(client_addr);
if ( (clientfd = ::accept(p_server->sk(), (sockaddr*)&client_addr, &len)) == SOCKET_ERROR)
{
emit p_server->haveNewMsg(QObject::tr("accept 出错"));
break;
}
//找出client数组中第一个为-1的单元存放已经连接的socket
for (i=0; i<FD_SETSIZE; i++)
{
if (client[i] <0)
{
client[i] = clientfd;
break;
}
}
if (i == FD_SETSIZE)
{
emit p_server->haveNewMsg(QObject::tr("error: too many clients!"));
break;
}
//sprintf(buff, "新连接来自%s", inet_ntoa(client_addr.sin_addr));
//emit p_server->haveNewMsg(buff);
emit p_server->newClient(inet_ntoa(client_addr.sin_addr), clientfd);
FD_SET(clientfd, &allset);
if (clientfd > maxfd)
maxfd = clientfd;
if (i>maxi)
maxi = i;
if (--nready <= 0)
continue;
}
for (i=0; i<=maxi; i++)
{
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset))
{
int n;
//客户端已经关闭连接
if ( (n = recv(sockfd, buff, MAX_LEN, 0 )) <= 0)
{
closesocket(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
emit p_server->haveNewMsg(QObject::tr("client closed"));
emit p_server->sClientClose(sockfd);
}
else //收到数据
{
buff[n] = 0;
emit p_server->haveNewMsg( buff, sockfd);
if (--nready <= 0)
break;
}
}
} //for (i=0; i<=maxi; i++)
}
return 0;
}

● 一个客户端的例子

void client::connectServer()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
//Winsock初始化错误
QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("Winsock初始化错误"), QMessageBox::Ok, 0);
msgBox.exec();
return;
}
if(wsaData.wVersion!=wVersionRequested)
{
//Winsock版本不匹配
QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("Winsock版本不匹配"), QMessageBox::Ok, 0);
msgBox.exec();
WSACleanup();
return;
} if ((m_sk = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("创建socket失败"), QMessageBox::Ok, 0);
msgBox.exec();
WSACleanup();
return;
} sockaddr_in addr;
addr.sin_family = AF_INET; bool ok;
unsigned short port = ui.portLineEdit->text().toInt(&ok, 10);
if (ok == false)
{
QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("端口输入错误"), QMessageBox::Ok, 0);
msgBox.exec();
closesocket(m_sk);
m_sk = -1;
WSACleanup();
return;
}
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (0 == ::connect(m_sk, (sockaddr *)&addr, sizeof(addr)))
{
updateMsgRecs(tr("连接成功..."));
HANDLE h = CreateThread(NULL, 0, &client::recvProc, (LPVOID)this, 0, 0);
CloseHandle(h);
}
else
{
QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("连接出错"), QMessageBox::Ok, 0);
msgBox.exec();
closesocket(m_sk);
m_sk = -1;
WSACleanup(); }
}

● winsock APIs
网络连接函数
socket 创建套接字
bind 绑定本机端口
connect 建立连接
listen 监听端口
accept 接受连接
recv, recvfrom 数据接收
send, sendto 数据发送
close, shutdown 关闭套接字
转换函数
inet_addr() 点分十进制数表示的IP地址转换为网络字节序的IP地址
inet_ntoa() 网络字节序的IP地址转换为点分十进制数表示的IP地址
字节顺序转换函数
htonl 4字节主机字节序转换为网络字节序
ntohl 4字节网络字节序转换为主机字节序
htons 2字节主机字节序转换为网络字节序
ntohs 2字节网络字节序转换为主机字节序
网络信息检索函数
gethostname 获得主机名
getpeername 获得与套接口相连的远程协议地址
getsockname 获得套接口本地协议地址
gethostbyname 根据主机名取得主机信息
gethostbyaddr 根据主机地址取得主机信息
getprotobyname 根据协议名取得主机协议信息
getprotobynumber 根据协议号取得主机协议信息
getservbyname 根据服务名取得相关服务信息
getservbyport 根据端口号取得相关服务信息
getsockopt/setsockopt 获取/设置一个套接口选项
ioctlsocket 设置套接口的工作方式
Windows网络编程 2 【转】的更多相关文章
- [转]Windows网络编程学习-面向连接的编程方式
直接附上原文链接:windows 网络编程学习-面向连接的编程方式
- Windows 网络编程
网络编程 API ,失败返回 -,错误代码 WSASYSNOTREADY 表示基础网络子系统没有准备好网络通行,WSAVERNOTSUPPORTED 表示 Socket 版本不支持,WSAEINPRO ...
- windows网络编程的一些理论
参考自<VC++深入详解> 这是我在看书时记录下来的东西. 注:下面的Socket其实都应该是socket 第14章网络编程 Socket是连接应用程序与网络驱动程序的桥梁,Socket在 ...
- Windows网络编程(C/C++服务器编程)
Windows服务器网络编程 Linux服务器网络编程
- windows 网络编程[转]
利用winsock编写网络应用程序服务端的步骤简述如下WSAStartup 初始化网络编程库 socket 创建套接字 bind 指定地址.端口,绑定套接字 listen 进入监听状态 accept ...
- Windows网络编程笔记4 -- Winsock 协议相关知识
Win32平台上的Winsock编程,Winsock是一个与协议无关的接口.以下协议是我们需要了解的: 网络协议的特征包括: 1. 面向消息 2. 面向连接和无线接 3. 可靠性和次序性 4. ...
- Windows网络编程笔记1
第一部分 传统网络API 传统的网络接口NetBIOS.重定向器.邮槽.命名管道等.第一,NetBIOS(Network Basic Input/Output System, NetBIOS)“网络基 ...
- windows网络编程-2015.12.29
在windows环境下,使用netstat命令查看网络状态,具体命令如下所示: netstat -ano | findstr listenport 在windows环境下,创建udp程序接收端,具体代 ...
- Windows网络编程笔记6 --- WinSock I/O 控制方法
Windows提供了两种方式“套接字模式”和“套接字I/O模型”,可对一个套接字上的I/O行为加以控制.套接字模式用于决定在随一个套接字调用时,那些 Winsock函数的行为.其中的模型包括括sele ...
随机推荐
- 使用jQuery ui创建模态表单
jQuery UI 是一个建立在 jQuery JavaScript 库上的小部件和交互库,可以使用它创建高度交互的 Web 应用程序. 在web页面的开发过程中,在添加元素的时候需要用到弹出窗口添加 ...
- 项目太多工作环境互相干扰?virtualenv 一招教你轻松解决。
写在之前 在上一篇文章 安装的 Python 版本太多互相干扰?以后再也不用担心这个问题了. 中我给大家介绍了一个 Python 版本的管理工具「pyenv」,可以很容易的安装不同的 Python 版 ...
- hibernate注解配置举例说明
Hibernate Annotation (Hibernate 注解) 进入:http://www.hibernate.org 说明文档: 英文:http://docs.jboss.org/h ...
- log4j配置信息
#INFO的日志信息输出到stdout和R这两个目的地,stdout和R的定义在下面的代码,可以任意起名.等级可分为OFF.FATAL.ERROR.WARN.INFO.DEBUG.ALLlog4j.r ...
- ICPC World Finals 2018 Problem H Single Cut of Failure
题目链接 题解视频 题解文档 解法概要: 问题可以转化为 考虑一个长为 $2n$ 的数组 $A$,$1$ 到 $n$ 这 $n$ 个整数每个恰在 $A$ 中出现 $2$ 次.判断是否存在一个长为 $n ...
- Quotes
A man's gotta do what a man's gotta do.
- [LOJ#2326]「清华集训 2017」简单数据结构
[LOJ#2326]「清华集训 2017」简单数据结构 试题描述 参加完IOI2018之后就是姚班面试.而你,由于讨厌物理.并且想成为乔布斯一样的创业家,被成功踢回贵系. 转眼,时间的指针被指向201 ...
- [NOI2009] 植物大战僵尸 [网络流]
题面: 传送门 思路: 这道题明显可以看出来有依赖关系 那么根据依赖(保护)关系建图:如果a保护b则连边(a,b) 这样,首先所有在环上的植物都吃不到,被它们间接保护的也吃不到 把这些植物去除以后,剩 ...
- BZOJ3309 DZY Loves Math 【莫比乌斯反演】
题目 对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(si ...
- 数组洗牌算法-shuffle
数组洗牌,最近直接的想法是从数组随机取出一个元素,放到另一个数组中,但是这样取出的元素会有重复,必须采取一定的方法保证: 1. 元素不能重复2. 元素被抽取的概率相等,即随机性 数组洗牌经典算法有两种 ...