winsock编程学习笔记
以下部分转自博客http://blog.csdn.net/phunxm/article/details/5085869
套接字地址(sockaddr、sockaddr_in)
/*
* Structure used by kernel to store most addresses.
*/
struct sockaddr {
u_short sa_family;/* address family,AF_X */
char sa_data[];/* up to 14 bytes of direct address */
};
包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是混杂在一起的。sa_data域的定义有些不确定性,注释暗示内容可能超过14个字节。这种不确定性是经过深思熟虑的。套接字是个非常强大的接口。多数人可能认为比Internet接口强不到哪里——大多数应用现在很可能都用它——套接字可被用于几乎任何种类的进程间通信,Internet(更精确的说是IP)只是其支持的协议簇中的一种。
/*
* Socket address, internet style.
*/
struct sockaddr_in {
short sin_family;/* internet address family */
u_short sin_port;/* port number */
struct in_addr sin_addr;/* internet address */
char sin_zero[];/* padding bits */
};
这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。注意sin_zero[8]是为了使sockaddr和sockaddr_in结构具有相同的尺寸,使用sockaddr_in的时候要把sin_zero全部设为零(使用memset函数)。
Winsock库的加载和卸载
要使用Windows Socket API进行编程,首先必须调用WSAStartup()函数初始化Winsock动态库。
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
- 参数一wVersionRequested:为我们要求初始化的Winsock版本号
- 参数二lpWSAData:为实际初始化成功的WSA(Windows Socket API)版本信息。
套接字的创建和释放
要使用套接字,首先必须调用socket()函数创建一个套接字描述符,就如同操作文件时,首先得调用fopen()函数打开一个文件。
// The socket function creates a socket that is bound to a specific service provider.
SOCKET socket(int af,// [in] Address family specification.
int type,// [in] Type specification for the new socket.
int protocol// [in] Protocol to be used with the socket that is specific to the indicated address family.
);
// The closesocket function closes an existing socket.
int closesocket(
SOCKET s// [in] Descriptor identifying the socket to close.
);
af:通信协议的协议族 ,AF_INET(IPv4)或 AF_INET6(IPv6)
type:指定要创建的套接字的类型。SOCK_STREAM, SOCK_ DGRAM,SOCK_RAW
protocol指定应用程序所使用的通信协议 :
IPPROTO_TCP, IPPROTO_UDP, 0(如果不想指定)
绑定套接字到指定的IP地址和端口
对于传输套接字,在执行收发数据前需要对本地端口进行绑定,这是因为传输层需要使用端口来区分具体的通信端点
// The bind function associates a local address with a socket.
int bind(
SOCKET s, // [in] Descriptor identifying an unbound socket.
const struct sockaddr FAR *name, // [in] Address to assign to the socket from the SOCKADDR structure.
int namelen // [in] Length of the value in the name parameter.
);
成功返回0,失败返回SOCKET_ERROR
TCP服务器设置套接字进入监听状态
服务器为了接受连接,首先使用socket()函数创建一个套接字,然后使用bind()函数将它绑定到一个本地地址(端口),再用listen()函数为到达的连接指定一个backlog。
// The listen function places a socket a state where it is listening for an incoming connection.
int listen(
SOCKET s,// [in] Descriptor identifying a bound, unconnected socket.
int backlog// [in] Maximum length of the queue of pending connections.
);
backlog参数指定了正在等待连接的最大队列长度。这个参数非常重要,因为服务器完全可能同时收到几个连接请求。假定backlog参数为2,如果三个客户机同时发出请求,那么头两个会被放在一个“待决”(等待处理)队列中,以便应用程序依次为它们提供服务。而第三个连接会造成一个WSAECONNREFUSED错误。注意,一旦服务器接受了一个连接(accept返回),那个连接请求就会从队列中删去,以便别人可继续发出请求。
该函数执行成功返回0,失败返回SOCKET_ERROR
客户端主动连接
// The connect function establishes a connection to a specified socket.
int connect(
SOCKET s,// [in] Descriptor identifying an unconnected socket.
const struct sockaddr FAR *name,// [in] Name of the socket to which the connection should be established.
int namelen// [in] Length of name.
);
客户端是连接的发起者(initiate),它通过调用connect()函数主动(active)连接服务器。参数二填写欲连接的目标服务器的地址。如果连接的计算机并没有在指定端口上监听,则connect()调用返回SOCKET_ERROR,WSAGetLastError()=WSAECONNREFUSED;另一种错误是WSAETIMEOUT,例如由于路由或网络故障,客户端迟迟接受不到服务器回馈的[SYN,ACK]信号。
TCP服务器接受客户连接请求
// The accept function permits an incoming connection attempt on a socket.
SOCKET accept(
SOCKET s,// [in] Descriptor identifying a socket that has been placed in a listening state with the listen function.
struct sockaddr FAR *addr,// [out] receives the address of the connecting entity, as known to the communications layer.
int FAR *addrlen// [out] the length of addr.
);
服务器进入listen状态后,循环调用accept()接受客户的连接。参数一为监听套接字;参数二为远端客户的地址信息;该函数返回一个套接字句柄,负责后续与该远端客户的会话通信。监听套接字总是默默无闻的在门口守望(listen),迎接(accept)客户的到来并安排服务员(会话套接字)接客。
该函数执行成功返回新的socket,失败返回SOCKET_ERROR
在一个已绑定或已连接的套接字上获取连接名和对方地址信息获取sockaddr
int getsockname (SOCKET s, struct sockaddr *name, int* namelen);
获取hostname
Host即通常意义上的机器名(Machine Name)或域名(Domain Name)。
int gethostname (char FAR *name, int namelen);
gethostname()函数可以取得调用主机的机器名。返回的这个name传给gethostbyname()调用可以取得相应IP地址。
struct hostent* gethostbyname(const char* name);
gethostbyname()函数主要用来做DNS解析,传入域名(例如www.baidu.com),返回hostent结构。struct hostent存放主机信息。
/*
* Structures returned by network data base library, taken from the
* BSD file netdb.h. All addresses are supplied in host order, and
* returned in network order (suitable for use in system calls).
*/
struct hostent {
char FAR *h_name; /* official name of host */
char FAR *FAR *h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char FAR *FAR *h_addr_list;/* list of addresses */
#defineh_addr h_addr_list[] /* address, for backward compat */
};
/* Microsoft Windows Extended data types */
typedef struct hostent HOSTENT, *PHOSTENT, *LPHOSTENT;
以下代码段获取百度(www.baidu.com)机器名和地址。
struct hostent *pHostBaiDu = gethostbyname("www.baidu.com");
printf("Host name: %s/n", pHostBaiDu->h_name);
printf("IP Address: %s/n", inet_ntoa(*((struct in_addr*)pHostBaiDu->h_addr)));
I/O通信
从I/O的角度来看,套接字也是文件,它提供了同文件读写(fread()/fwrite())对应的收发数据操作接口:send()/recv()。
发送数据
// The send function sends data on a connected socket.
int send(
SOCKET s,// [in] Descriptor identifying a connected socket.
const char FAR *buf,// [in] Buffer containing the data to be transmitted.
int len,// [in] Length of the data in buf.
int flags// [in] Indicator specifying the way in which the call is made.
);
send()函数在一个已连接的套接字s上执行数据发送操作。对于客户机而言,发送的目标地址即connect()调用时所指定的地址;对于服务器而言,发送的目标地址即accept()调用所返回的地址。发送的内容为保存在缓冲区buf中,发送的内容长度为len。最后一个参数flags,通常情况下填0。
成功返回发送字节数,出错返回SOCKET_ERROR
接收数据
// The recv function receives data from a connected or bound socket.
int recv(
SOCKET s,// [in] Descriptor identifying a connected socket.
char FAR *buf,// [out] Buffer for the incoming data.
int len,// [in] Length of buf.
int flags// [in] Flag specifying the way in which the call is made.
);
recv()函数在一个已连接的套接字s上执行数据接收操作。对于客户机而言,数据的源地址即connect()调用时所指定的地址;对于服务器而言,数据的源地址即accept()调用所返回的地址。接收的内容为保存至长度为len的缓冲区buf,最后一个参数flags,通常情况下填0。
成功返回接收的数据的字节数量,失败返回SOCKET_ERROR,如果接受数据时网络中断返回0。
关闭套接字(TCP连接)
// The shutdown function disables sends or receives on a socket.
int shutdown(
SOCKET s,// [in] Descriptor identifying a socket.
int how// [in] Flag that describes what types of operation will no longer be allowed.
);
WinSock TCP C/S通信示例
简单通信示例:
客户端代码:
#include <winsock2.h>
#include <stdio.h>
#define SERVPORT 5050 // 端口为5150
#define MAXDATASIZE 100
#define SERVIP “127.0.0.1” // 服务器IP地址为“127.0.0.1”,
#pragma comment(lib,"ws2_32.lib")
void main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET sConnect;
SOCKADDR_IN serverAddr;
int recvbytes;
char buf[MAXDATASIZE];
WSAStartup(MAKEWORD(,), &wsaData);
sConnect = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVPORT);
serverAddr.sin_addr.s_addr = inet_addr(SERVIP);
memset(&(serverAddr.sin_zero), , sizeof(serverAddr.sin_zero));
if(
connect(sConnect, (SOCKADDR*)&serverAddr,sizeof(SOCKADDR))==SOCKET_ERROR)
{
printf("connect failed!\n");
return;
}
recvbytes = recv(sConnect, buf, MAXDATASIZE, );
if (recvbytes == SOCKET_ERROR){ printf("recv failed!\n");}
else{buf[recvbytes] = '\0';printf("%s\n",buf); }
closesocket(sConnect);
WSACleanup();
}
服务端代码:
#include <winsock2.h>
#include <stdio.h>
#define SERVPORT 5050
#pragma comment(lib,"ws2_32.lib")
void main(void)
{
WSADATA wsaData;
SOCKET sListen; // 监听socket
SOCKET sClient; // 连接socket
SOCKADDR_IN serverAddr; // 本机地址信息
SOCKADDR_IN clientAddr; // 客户端地址信息
int clientAddrLen; // 地址结构的长度
int nResult;
WSAStartup(MAKEWORD(,), &wsaData);
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVPORT);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(serverAddr.sin_zero), , sizeof(serverAddr.sin_zero));
nResult = bind(sListen, (SOCKADDR *)&serverAddr, sizeof(SOCKADDR));
if (nResult == SOCKET_ERROR)
{
printf("bind failed!\n");
return;
}
listen(sListen, );
while()
{
clientAddrLen = sizeof (SOCKADDR);
sClient = accept(sListen, (SOCKADDR *)&clientAddr, &clientAddrLen);
if(sClient == INVALID_SOCKET){printf("Accept failed!"); }
else{
printf("Accepted client: %s : %d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
nResult = send(sClient, "Connect success!", , );
if (nResult == SOCKET_ERROR){printf("send failed!");}
}
closesocket(sClient);
}
closesocket(sListen);
WSACleanup();
}
winsock编程学习笔记的更多相关文章
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- Linux Shell编程学习笔记——目录(附笔记资源下载)
LinuxShell编程学习笔记目录附笔记资源下载 目录(?)[-] 写在前面 第一部分 Shell基础编程 第二部分 Linux Shell高级编程技巧 资源下载 写在前面 最近花了些时间学习She ...
- DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- 多线程编程学习笔记——async和await(一)
接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...
- 多线程编程学习笔记——async和await(二)
接上文 多线程编程学习笔记——async和await(一) 三. 对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...
- 多线程编程学习笔记——async和await(三)
接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五. 处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...
- 多线程编程学习笔记——使用异步IO(一)
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端
接上文 多线程编程学习笔记——使用异步IO 二. 编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...
- 多线程编程学习笔记——异步调用WCF服务
接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...
随机推荐
- 修改idea打开新窗口的默认配置
使用idea开发maven项目时,发现使用新窗口创建一个项目时,例如file-settings的maven库配置都是用的用户下的maven库,如何配置一个全局的maven配置呢,操作如下: File- ...
- Thread-方法以及wait、notify简介
Thread.sleep()1.静态方法是定义在Thread类中.2.Thread.sleep()方法用来暂停当前执行的线程,将CPU使用权释放给线程调度器,但不释放锁(也就是说如果有synchron ...
- 关于springboot aop 俩次调用的问题 aop多次调用
由于我在springboot 启动类中 给我的切面类进行了赋值 即@Bean 然而我在切面类中加了@Component 导致 springboot 注入了俩个 bean 所以导致 aop 多次执行 ...
- 当x,y和theta都是向量的时候如何计算损失
function J = computeCost(X, y, theta) %COMPUTECOST Compute cost for linear regression % J = COMPUTEC ...
- jenkins内部分享ppt
持续集成Continuous integration简介(持续集成是什么) .持续集成源于极限编程(XP),是一种软件实践,软件开发过程中集成步骤是一个漫长并且无法预测的过程.集成过程中可能会爆 ...
- 【Eclipse】添加builder实现NDK的自动编译
最近在做NDK相关的东西,Eclipse里面java的自动编译很方便,每次改动后就能自己编译显示错误,而NDK的C/C++文件就需要保存后再手动点build. 研究了下发现java code的自动编译 ...
- 年终培训关于磁盘冗余阵列、热备、群集、负载均衡、云计算、F5、Nginx等的概念和基本原理
在系统部署实施过程中,客户往往会关注系统的可用性方面的指标. 对于一个具备高可用性的系统来说, 多机部署方案是必不可少的. 我们这个知识分享,就从多个不同层面来介绍多机部署方案. ---------- ...
- ElasticSearch聚合分析
聚合用于分析查询结果集的统计指标,我们以观看日志分析为例,介绍各种常用的ElasticSearch聚合操作. 目录: 查询用户观看视频数和观看时长 聚合分页器 查询视频uv 单个视频uv 批量查询视频 ...
- SpringBoot入门之Thymeleaf的使用
在.net的MVC3 或更高版本等支持 Razor 的框架里使用cshtml,Razor是一种简单的编程语法,用于在网页中嵌入服务器端代码.在使用springboot开发mvc时也有与.net类似的视 ...
- C# 微信公众号开发--准备工作
前言 最初打算熟悉下微信开发打算用node.js开发,结果底气不足先用C#开发,先踩了踩坑. 准备工作 微信公众平台开发者文档. 这个先多看几遍. 测试公众号,申请开通后会看到微信号,appID,ap ...