以下部分转自博客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编程学习笔记的更多相关文章

  1. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  2. Linux Shell编程学习笔记——目录(附笔记资源下载)

    LinuxShell编程学习笔记目录附笔记资源下载 目录(?)[-] 写在前面 第一部分 Shell基础编程 第二部分 Linux Shell高级编程技巧 资源下载 写在前面 最近花了些时间学习She ...

  3. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  4. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  5. 多线程编程学习笔记——async和await(二)

    接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...

  6. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  7. 多线程编程学习笔记——使用异步IO(一)

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  8. 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

    接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...

  9. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

随机推荐

  1. windows phone开发-windows azure mobile service使用入门

    在使用azure之前,我一直只能做本地app,或者使用第三方提供的api,尽管大多数情况下够用,但是仍不能随心所欲操纵数据,这种感觉不是特别好.于是在azure发布后,我就尝试使用azure来做为个人 ...

  2. iOS-实现后台长时间运行

    前言 一般APP在按下Home键被挂起后,这时APP的 backgroundTimeRemaining 也就是后台运行时间大约只有3分钟,如果在退出APP后,过十几二十二分钟或者更长时间再回到APP, ...

  3. 【转】ASP.NET Core MVC 配置全局路由前缀

    本文地址:http://www.cnblogs.com/savorboard/p/dontnet-IApplicationModelConvention.html作者博客:Savorboard 前言 ...

  4. Kafka项目实战-用户日志上报实时统计之应用概述

    1.概述 本课程的视频教程地址:<Kafka实战项目之应用概述> 本课程是通过一个用户实时上报日志来展开的,通过介绍 Kafka 的业务和应用场景,并带着大家搭建本 Kafka 项目的实战 ...

  5. Mysql、MongoDB对比和使用场景

    MongoDB: 更高的写入负载 默认情况下,MongoDB更侧重高数据写入性能,而非事务安全,MongoDB很适合业务系统中有大量“低价值”数据的场景.但是应当避免在高事务安全性的系统中使用Mong ...

  6. 一、Windows下Git的安装与配置

    一.下载Git安装包 1.打开Git的官方网站:https://git-scm.com/ 2.找到下载页:https://git-scm.com/downloads 3.找到Windows版本下载页面 ...

  7. ELK(elasticsearch+kibana+logstash)搜索引擎(二): elasticsearch基础教程

    1.elasticsearch的结构 首先elasticsearch目前的结构为 /index/type/id  id对应的就是存储的文档ID,elasticsearch一般将数据以JSON格式存储. ...

  8. 操作Linux系统环境变量的几种方法

    一.使用environ指针输出环境变量 代码如下: #include<stdio.h> #include<string.h> #define MAX_INPUT 20 /* 引 ...

  9. jQuery学习(1)猜数字游戏

      jQuery是一个快捷.小型且特征丰富的JavaScript库.它使得HTML文档遍历及操作,事件处理,动画,Ajax等更简洁方便.它通过调用一个简单易用的API,就能在各种浏览器中使用.由于jQ ...

  10. 菜鸟入门【ASP.NET Core】8:Middleware管道介绍、自己动手构建RequestDelegate管道

    中间件:是汇集到以处理请求和响应的一个应用程序管道的软件. 每个组件: 可以选择是否要将请求传递到管道中的下一个组件. 之前和之后调用管道中的下一个组件,可以执行工作. 使用请求委托来生成请求管道.  ...