C 语 言 设 计 一 个 Windows Socket

对程序员来说,可以把socket看成一个文件指针,只要向指针所指的文件读写数据,就可以实现双方通信。利用socket进行通信,有两种主要方式。

 

第一种是面向连接的流方式,两个通信的应用程序之间先要建立一种连接链路,数据才能被正确传送接收。这种方式对应的是TCP协议。特点是:通信可靠,对数据有校验和重发机制,通常用作数据文件的传输,如ftptelnet

 

第二种是无连接的数据报文方式,这时两台计算机像是把数据放在一封信里通过网络寄给对方,信在传输过程中可能会残缺不全,而且后发的信可能会先被收到,对应的是UDP协议。由于取消重发校验机制,能够达到较高的通信速率,可以用作一些对数据可靠性要求不高的通信,如实时语音,图像传送,广播信息。

 

ISOOSI网络七层协议中,WINSOCK主要负责是控制数据的输入输出,也就是传输层和网络层,屏蔽了数据链路层和物理层,给windows下的网络编程带了巨大变化。

 

l         WINSOCK的编程特点

 

网络通信中,由于网络拥挤或一次发送的数据量过大等原因,经产会发生交换的数据在短时间内不能传送完,收发数据的函数因此不能返回,这种现象叫阻塞。WINSOCK对有可能阻塞的函数提供两种处理方式:

 

1.         阻塞方式:收发数据的函数在被调用后一直要到传送完毕或者出错才能返回,期间,除了等待网络操作的完成不能进行任何操作。用户可能会因为长时间等待而关闭主窗口。

2.         非阻塞方式:函数被调用后立即返回,当网络操作传送完成后由WINSOCK给应用程序发送一个消息通知操作完成,可以根据发送的消息传出的参数判断操作是否正常。

 

l         WINSOCK基本的API

 

WSAStartup():初始化

函数原型:

int PASCAL FAR WSAStrartup(WORD wVersionRequest,LPWSADATA  lpWSAData);

 

windows socketDLL形式提供,为了完成一系列初始化操作,每一个使用windows socket的应用程序必须进行WSAStartup()调用,只有完成成功的调用后才能使用socket

 

wVersionRequest :欲使用的windows socket API版本,这是一个WORD类型的整数,它的高位字节定义是次版本号,低位是主版本号。

 

lpWSAData:指向WSDATA资料的指针。

 

传回值:0表示成功,失败返回其它相应结果(失败的原因)。

 

Socket():创建一个Socket

函数原型:

SOCKET Scoket(int af, int type, int proctocol);

 

该函数功能与文件操作中的fopen类似。

 

afaddress family。一般填写AF_INET 表示是在Internet上的sockettypesocket的类型,当采用流连接方式时写SOCK_STREAM,用数据报文方式写SOCK_DGRAMproctocol一般为0,表示对两种类型的socket分别采用默认的TCPUDP传输协议。函数返回值是WINSOCK定义的一种数据类型SOCKET,实际上是个整形数据,创建成功时,返回WINSOCK分配给程序的socket编号,后面调用传输函数,可以把它当作指针一样引用。创建失败返回INVALID_SOCKET

 

bind():为创建socket指定通信对象。

函数原型:

int bind(SOCKET s,struct sockaddr_in * name, int namelen);

 

成功创建socket后,就应该选定通信对象。首先是自己的程序要与网上的哪台计算机通话;其次在多任务时,该台计算机可能会有几个程序在工作,必须指定要与哪个程序通信。前者可通过网络IP来确定,后者通过端口号确定。端口号表示同一台计算机上不同的应用程序,可以在065535之间任选,在编制自己通信程序时,应指定端口号大于1024TCP——21UDP——69

 

s:上一步创建好的套接字。

name:描述通信对象地址信息的结构体的指针,namelen是该结构体的长度。

 

struct socketadd_in{

      short  sin_family;    //一套地址族,通常设置为AF_INET(表示Internet上的socket)

      unsigned short  sin_port;  //端口号

      struct  in_addr;     //IP地址

      char   sin_zero[8];

}

//使该结构大小和SOCKADDR结构大小相同(SOCKADDR是一个无符号short型和长度为14char型数组构成),sockadd_in加入这个数组长度也是16,目的是方便于地址操作。

 

IP地址in_addr的定义如下:

 

struct in_addr{

     union  {

          struct{

              unsigned char s_b1;

                   s_b2,s_b3,s_b4;

              }  S_un_b;

          struct{

              unsigned short  s_w1, s_w2;

              }  S_un_w;

          unsigned long S_addr;

        } S_un;

};

 

对一个IP地址是“10.14.25.90sockaddr_in结构中的sin_addr可以被这样几种方法赋值:

M1

sin_addr.S_un.S_un_b.s_b1=10;

sin_addr.S_un.S_un_b.s_b2=14;

sin_addr.S_un.S_un_b.s_b3=25;

sin_addr.S_un.S_un_b.s_b4=90;

M2:

sin_addr.S_un.S_sun_w.s_w1=(14<<8)|10;

sin_addr.S_un.S_sun_w.s_w2=(90<<8)|25;

M3:

sin_addr.S_un.S_addr=(90<<24)|(25<<16)|(14<<8)|10;

 

listen():设置等待连接状态

函数原型:

int listen(SOCKET s, int backlog);

 

对于服务器的程序,当申请到socket,并指定通信对象为INADDR_ANY之后,就应该等待一个客户机的程序要求连接,listen()就是把一个socket设置这种状态的函数。backlog表示等待连接队列长度,可取15,如果服务器已经和其它客户程序连接,则后来这个连接被放在队列中,等待服务器空闲的时候连接。当队列达到指定长度backlog,再来连接会被拒绝。

 

accept():接收连接请求。

函数原型:

SOCKET accept(SOCKET s, struct sockaddr_in *  addr , int * addrlen);

 

接收到连接后,会为这个连接建立一个新的socket用来与对方通信,并把它作为返回值,新建的socket与原来的socket有相同的特性,包括端口号,而原来的socket被释放,用于等待其它连接请求。新的SOCKET才是与客户端通信的实际的SOCKET。所以参数中SOCKET称为监听SOCKET,负责连接,而accpet返回的SOCKET成为会话SOCKETaddraddrlen返回客户机的sockaddr_in结构体。

 

connect():请求建立连接。适用于客户机。

函数原型:

int connect (SOCKET s,struct sockaddr_in * name, int namlen);

 

send()/recv():发送接收数据

函数原型:

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

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

 

s是连接的socketbuflen是发送接收的数据包及其长度。flags一般为0recv()实际上是接收send()的数据包,当读到的数据字节少于规定接收的数目时,就把数据全部接收,返回实际字节数。当多于规定值时,流方式下,剩余字节由下一个recv()读出;在数据报文方式下,多余数据将被丢弃,这两个函数出错返回SOCKET_ERROR

 

数据报文方式通信的socket,由于事先不建立连接,所以跳过了connect()而直接调用以下方式:

 

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

int sendto   (SOCKET s, char *buf,  int len,  int flags, struct sockaddr_into, int *tolen);

 

from,fromlen,to,tolen分别表示接收发送数据对象。

 

closesocket():关闭socket

函数原型:

closesocket(SOCKET s);

 

通信结束,关闭socket

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值