Socket(二)

2)提出连接申请
  在成功调用了socket函数后,对客户端来说就是与服务器端建立连接。同样,建立连接需要两个函数:connectWSAConnect。前者是标准的Socket函数,后者是微软的扩展函数。


int PASCAL FAR WSAConnect ( SOCKET s, const struct sockaddr FAR *name, int namelen );
数:

s所使用的套接字描述符
name
一个sockaddr结构,sockaddr结构是一个通用的结构,它只是简单地定义了一个字节数组,在TCP/IP下一般将其解释为sockaddr_in结构,第3个参数则是该结构的长度,一般用sizeof函数来取得
namelen
name的长度

示例代码:
sockaddr_in sock;

sock.sin_family=AF_INET;
sock.sin_port=htons(80);
sock.sin_addr.s_addr=inet_addr(“202.205.210.1”);
if(connect(sk,(sockaddr*)&sock,sizeof(sock)==SOCKET_ERROR)
{ 
//
错误处理
}

sockaddr_in结构体

struct sockaddr_in {

       //地址族(指定地址格式) ,设为AF_INET

       short sa_family;

       u_short  sin_port; //端口号

       struct in_addr sin_addr; //IP地址

       char sin_zero[8]; //空子节,设为空

       }

sockaddr结构体

struct sockaddr{

       u_short  sa_family;

       char       sa_data[14];

       }

 

这里有一点要说明的是,用于填写sockaddr_in结构的值必须是以网络字节顺序表示的值,而不能直接使用本机字节顺序的值。之所以这样规定是因为在网络上存在不同的系统,不同的系统中数据存储时所采用的字节排列顺序是不同的,有的是高字在前,低字在后,而有的刚好相反。为了统一,规定了一个所谓的网络字节顺序。htonl函数可以将本地的unsigned long数据转换为网络字节顺序的数据。htons则是将unsigned short的数据转换为网络字节顺序的数据。而ntohsntohl的功能则是刚好相反。另外,sockaddr_in结构的sin_addr.s_addr成员要求是用来描述对方地址的一个值,即网际地址值,而实际应用中,我们得到的大多是IP地址或域名,如202.210.205.1www.cfan.cn.net,可以用inet_addr函数将点分法表示的IP地址转换为所要求的值,可以用gethostbynameWSAAsynGetHostbyName取回用易用名表示的主机的信息。gethostbyname函数调用成功会返回一个hostent结构的指针,若错误则返回NULL。下面介绍一下gethostbyname函数的用法。
hostent *host;

.......
host=gethostbyname(“www.cfan.cn.net”)
if(host==NULL)
{ 
//
错误处理
sock.sin_addr.s_addr=*((unsigned long*)host
h_addr_list[0]);
.....
.


  三、数据的传送和接收

  于这里建立的是SOCK_STREAM类型的连接,故发送可以采用的函数有sendWSASend,而接收可以采用recvWSARecv,同样,全小写的函数是标准的Socket函数,WSA开头的是微软的扩展函数. Sendrecv调用成功返回所发送或接收的字节数,如果调用失败则返回SOCKET_ERROR!
int PASCAL FAR WSASend ( SOCKET s, const char FAR *buf,int len, int flags );
参数:

s发送操作所用的套接字描述符
buf
发送的数据缓冲区的地址,为char*类型,至于其它类型的数据可以用强制类型转换(char*)。在接收端再用强制类型转换回来!
len buf
所发送的缓冲区的大小,也就是所要发送的字节数!
flags
一个附加标志,可以为0MSG_OOBMSG_DONTROUTE. 如果对所发送的数据没特殊要求,直接设为0
  对于Datagram Socket而言,若是 datagram 的大小超过限制,则将不会送出任何资料,并会传回错误值。对Stream Socket 言,Blocking 模式下,若是传送系统内的储存空间不够存放这些要传送的资料,send()将会被block住,直到资料送完为止;如果该Socket被设定为 Non-Blocking 模式,那么将视目前的output buffer空间有多少,就送出多少资料,并不会被 block 住。flags 的值可设为 0 MSG_DONTROUTE MSG_OOB 的组合。

int PASCAL FAR recv( SOCKET s, char FAR *buf, int len, int flags );
参数说明同发送。

示例代码(send函数)
SOCKET sk;

char szTest[]=“This is an example!”
int iRet;
......(
这里省略创建套接字,连接...)
iRet=send(sk,szTest,strlen(szTest),0);
if(iRet==SOCKET_ERROR) 
{
//
错误处理
}
else if(iRet!=strlen(szTest))
MessageBox(NULL,“
未发送所有的数据”,“警告”,MB_OK);
示例代码(recv函数)
SOCKET sk;
char szTest[20]
int iRet;
......(
这里省略创建套接字,连接......)
iRet=recv(sk,szTest,20,0);

if(iRet==SOCKET_ERROR)
{
//
错误处理
}

szTest[iRet]=`\0`;//这一行代码不可少!因为recv函数不会自动将数据缓冲末尾设为表示数据结束的空中止符(`\0`),因此,一不留神就会出现缓冲区越界。当然也可以在调用recv函数前先将缓冲区清0(ZeroMemorymemset),不过还是建议加上这一句。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值