Winsock基础编程

Socket的英文原义是“孔”或“插座”。作为BSD
UNIX的进程通信机制,取后一种意思。通常也称作“套接字”,用于描写叙述IP地址和port,是一个通信链的句柄。在Internet上的主机一般执行了多个服务软件,同一时候提供几种服务。每种服务都打开一个Socket,并绑定到一个port上,不同的port相应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机宛如布满各种插座的房间,每一个插座有一个编号,有的插座提供220伏交流电,
有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就能够得到不同的服务。

1 基于TCP

它是面向连接的,稳定的网络通信。它的通信流程例如以下所看到的:

<1>TCP 连接建立

TCP连接的建立须要经过三次握手,所谓的三次握手例如以下所看到的:

  • client向server发送一个SYN J
  • server向client响应一个SYN K,并对SYN J进行确认ACK J+1
  • client再想server发一个确认ACK K+1

通俗的讲就是:

A:B,我想连接你

B:A,我看到了,你连接吧

A:那我连了

B:等待接受。。。

<2>TCP连接终止

TCP连接的终止须要以下四次挥手。

  • 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
  • 还有一端接收到FIN M之后,运行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,由于FIN的接收意味着应用进程在对应的连接上再也接收不到额外数据;
  • 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
  • 接收到这个FIN的源发送端TCP对它进行确认。

通俗的讲就是:

A:我要关了啊

B:你要关吗?

B:这么长时间没反应,那我要关了。

A:看到你要关了

B:关闭

<3>TCP稳定性的保证

它採用的是确认重传机制,没发送一个消息它都会启动一个定时器,观察一定时间内有没有收到对方的确认信息,假设收到就算了,没收到它就以为消息没发过去然后就会又一次发送。正是因为这样的确认重传机制导致了TCP通信的效率没UDP高。

2 基于UDP

它是提供面向无连接的,不可靠的通信协议。它的通信步骤例如以下图所看到的:

3 相关函数介绍

<1>WSAStartup函数

intPASCAL FAR WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

wVersionRequested:用来指定载入Winsock库的版本号,低位字节代表主版本号号,高位字节代表副版本号号。通经常使用MAKEWORD(x,y)表示版本号号,当中x表示高位自己,y表示低位字节。

lpWSAData:返回的指向WSADATA结构体的指针,这个结构体里面包括着主要关于版本的信息。

返回值:

成功:返回0。

失败:

WSASYSNOTREADY:表示网络设备没有准备好。

WSAVERNOTSUPPORTTED:Winsock的版本号信息号不支持。

WSAEINPROGRESS:一个堵塞式的Winsock1.1存在于进程中。

WSAEPROCLIM:已经达到Winsock的使用量的上限。

WSAEFAULT:lpWSAData不是一个有效的指针。

注意:

这个函数winsock的初始化函数,假设它失败那么后面的全部相关Winsock的都不会被运行。

<2>socket函数

SOCKETsocket(int af,  int type,  int proctocol);

这个socket有点类似句柄,或者文件指针。

af:address family(地址族),一般都填AF_INIT,表示是在Internet上的Socket;

type:Socket的类型,当採用流连接方式时用SOCK_STREAM,用数据报文方式时用

SOCK_DGRAM。

proctocol:一般都为0,表示对2种类型的Socket分别採用缺省的TCP和UDP传输协议。

<3>bind函数

int bind(SOCKET s,  const sockaddr* name,  intnamelen);

这个函数的作用是把socket绑定到指定的IP地址以及port。

s:要绑定的socket

name:指向sockaddr*的结构体指针。结构体例如以下所看到的:

struct sockaddr
{
u_shortsa_family;
char sa_data[14];
};

可是通常在Winsock中用sockaddr_in结构体取代这个结构体,它例如以下所看到的:

struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

当中in_addr是这样一个结构体

struct in_addr {
union {
struct{ UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct{ USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
}

我们能够看到这个结构体里面就有一个union,字节长度是4个字节。能够利用这个结构方便的将点分十进制格式的IP地址转换成u_long类型,而且将结果赋予S_addr。

namelen: name所指向的结构体的长度

注意:

port号的范围是0-65536,可是1024一下的port都被预占,所以在指定port号的要在其上面。

另外,in_addr和sockaddr结构体的字节长度相等。

<4>listen函数

int listen(SOCKET s,  int backlog);

s: 启动监听的socket

backlog:等待连接队伍的最大长度,一般设置为1-5

<5>accept函数

SOCKET accept(SOCKET s,  sockaddr* addr,  int* addrlen);

s:监听状态的套接字

addr:保存client的信息,ip,port号等

addrlen:地址信息的长度,这也是个返回值

注意:

当调用accept函数的时候,程序就会等待client调用connect函数发生连接。

<6>connect函数

Int connect(SOCKET s,const sockaddr*name,int namelen);

s:连接的套接字

addr:欲要连接的地址

addrlen:地址信息的长度

<7>send/recv函数

int send(SOCKET s,const char* buf,int len,int flags);

int recv(SOCKET s,const char* buf,int len,int flags);

s:发送信息的socket

buf:发送/接受 数据的缓冲区

len:发送/接受 信息的长度

flags:影响函数行为的值,一般设置为0

注意:

发送的长度一般要依据详细的字节长度来指定,接受的长度则是整个缓冲区的长度。

<8>sendto/recvfrom 函数

int recvfrom(SOCKET s, char* buf, int len,int flags, struct sockaddr* from, int* fromlen);

int sento(SOCKET s, char* buf, int len ,int flags , struct sockaddr* to , int tolen);

s:己方的socket

buf:缓冲区

len:缓冲区长度

flags:一般设置为0,是个影响函数行为的參数

from/to:返回值,表示对方的地址信息 / 输入的对方地址信息

fromlen/tolen:返回值,表示对方地址信息的长度 / 输入的对方地址信息长度

<9> closesocket函数

int closesocket(socket s);

关闭一个socket。

UDP的演示样例程序:

//server
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") void main()
{
WORD wVersionRequested;
WSADATA wsaData;
interr;
wVersionRequested = MAKEWORD(1,1);
err =WSAStartup(wVersionRequested,&wsaData);
if(err!= 0)
{
return;
} if(LOBYTE(wsaData.wVersion)!= 1 || HIBYTE(wsaData.wVersion) != 1 )
{
WSACleanup();
return;
} SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr =htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR) );
charrecvBuf[100];
charsendBuf[100];
chartempBuf[200]; SOCKADDR_IN addrClient;
int len= sizeof(SOCKADDR); while(1)
{
recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);
if('q' == recvBuf[0])
{
sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);
printf("chat end");
}
sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf);
printf("%s\n",tempBuf); printf("please input data:\n");
gets(sendBuf);
sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);
}
closesocket(sockSrv);
WSACleanup();
}
//client
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") void main()
{
WORD wVersionRequested;
WSADATA wsaData;
interr; wVersionRequested = MAKEWORD(1,1);
err =WSAStartup(wVersionRequested,&wsaData);
if(err!= 0)
{
printf("WSAStartup failed\n");
return;
}
if(LOBYTE(wsaData.wVersion)!= 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return;
} SOCKET sockClient =socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(6000); charrecvBuf[100];
charsendBuf[100];
chartempBuf[200];
int len= sizeof(SOCKADDR); while(1)
{
printf("please input data\n");
gets(sendBuf);
sendto(sockClient,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrServer,len);
recvfrom(sockClient,recvBuf,100,0,(SOCKADDR*)&addrServer,&len);
if('q' == recvBuf[0])
{
sendto(sockClient,"q",strlen("q")+1,0,(SOCKADDR*)&addrServer,len);
printf("chat end\n");
break;
}
sprintf(tempBuf,"%s say :%s",inet_ntoa(addrServer.sin_addr),recvBuf);
printf("%s\n",tempBuf); }
closesocket(sockClient);
WSACleanup();
}

Winsock基础编程的更多相关文章

  1. Winsock API编程介绍

    相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...

  2. 6、50道JAVA基础编程练习题跟答案

    50道JAVA基础编程练习题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 程序分析 ...

  3. 老李分享: 并行计算基础&编程模型与工具 1

    老李分享: 并行计算基础&编程模型与工具   在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如 ...

  4. 【Socket】Java Socket基础编程

    Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要讲解Socket的基础编程.Socket用在哪呢,主要用在进程间,网络间通信.本篇比较长,特别做了个目录: 一.Socket通信基 ...

  5. go基础编程 day-1

    Go语言的特性 开启了学习新的语言路程,记录每天学习的笔记,与大家一起分享. ①.自动垃圾回收 ②.更丰富的内置类型 ③.函数多返回值 ④.错误处理 ⑤.匿名函数和闭包 ⑥.类型和接口 ⑦.并发编程 ...

  6. Winsock网络编程笔记(1)----入门

    今天第一次接触winsock网络编程,看的资料是Windows网络编程第二版.通过博客记住自己的看书笔记.. 在这里贴出第一个程序,虽然程序什么都没做,但以此作为入门,熟悉其网络编程风格.. #inc ...

  7. 简单的TSQL基础编程格式,存储过程,视图

    这里简单整理一下数据库简单的编程,变量定义,赋值,分支语句和循环(这里以Sqlserver),以及存储过程格式 首先是变量定义,赋值,分支语句 --======TSQL数据库基础编程,定义变量,赋值, ...

  8. Hadoop 综合揭秘——MapReduce 基础编程(介绍 Combine、Partitioner、WritableComparable、WritableComparator 使用方式)

    前言 本文主要介绍 MapReduce 的原理及开发,讲解如何利用 Combine.Partitioner.WritableComparator等组件对数据进行排序筛选聚合分组的功能.由于文章是针对开 ...

  9. 计算概论(A)/基础编程练习(数据成分)/3:整数的个数

    #include<stdio.h> int main() { ] = {}; // 输入k个正整数 scanf("%d",&k); // 循环读入和进行算术 w ...

随机推荐

  1. c++ 复制构造函数和赋值函数

    c++ 自动提供了下面这些成员函数 1默认构造函数 2.复制构造函数 3.赋值操作符 4.默认析构函数 5.地址操作符 赋值构造函数copy construtor 用于将一个对象复制到新创建的对象中, ...

  2. 省部级干部list

    省部级干部表 省(市.自治区) 省(市)委书记 省(市)人大主任 省(市)长 省(市)政协主席 北京市 郭金龙 杜德印 王安顺 吉林 天津市 黄兴国 肖怀远 黄兴国 臧献甫 上海市 韩正 殷一璀(女) ...

  3. cocos2d-x游戏开发系列教程-超级玛丽07-CMGameMap(六)-马里奥跳跃

    当w键按下时,马里奥执行跳跃动作 执行跳跃动作也是在MarioMove函数中调用的

  4. android自定义控件 onMeasure() 测量尺寸

    上次讲的自定义控件刷新点屏幕的任意地方都会刷新,而且在xml里自定义控件下面放一个textview的话,这个TextView是显示不出来的,不只这个,以前的几个自定义控件都是 为什么呢?今天来讲下on ...

  5. AlertDialog具体解释

    对话框介绍与演示样例         对话框在程序中不是必备的,可是用好对话框能对我们编写的应用增色不少.採用对话框能够大大添加应用的友好性.比較经常使用的背景是:用户登陆.网络正在下载.下载成功或者 ...

  6. 循环调用修正sic86 2改后的(除了第一年有点诡异,其他年份可以正常修复)

    create or replace procedure rebuild_sic86_wyl(pi_aac001 in number, po_fhz out varchar2, po_msg out v ...

  7. 【集训笔记】母函数【母函数模板】【HDOJ1028【HDOJ1085

    以下资料摘自 http://www.cnblogs.com/wally/archive/2012/07/13/hdu1028_1085_1171_.html 生成函数是说,构造这么一个多项式函数g(x ...

  8. 函数嵌套 lisp表达式求值

    问题 D: lisp表达式求值 时间限制: 1 Sec  内存限制: 128 MB提交: 105  解决: 43[提交][状态][讨论版] 题目描述 lisp是一种非常古老的计算机语言,是由约翰·麦卡 ...

  9. (Problem 10)Summation of primes

    The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. Find the sum of all the primes below two milli ...

  10. solrCloud+tomcat+zookeeper配置

    一.环境准备: Solr版本:4.7.0 下载地址:http://www.apache.org/dyn/closer.cgi/lucene/solr/4.7.0 Tomcat版本:6.0.39 下载地 ...