您好,欢迎来到好走旅游网。
搜索
您的当前位置:首页socket中运用到的函数详解

socket中运用到的函数详解

来源:好走旅游网


WSAStartup 函数原型 注释 成员 返回值 错误代码 WSAStartup 函数原型 注释 成员 返回值 错误代码 展开

编辑本段

WSAStartup

简介

WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字异步)的启动命令。是Windows下的网络编程接口软件 Winsock1 或 Winsock2 里面的一个命令(Ps:Winsock 是由Unix下的BSD Socket发展而来,是一个与网络协议无关的编程接口)。

详细说明

为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。使用Socket的程序在使用Socket之前必须调用WSAStartup函数。该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;操作系统利用第二个参数返回请求的Socket的版本信息。当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。

编辑本段函数原型

#include

int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );

wVersionRequested Windows Sockets API提供的调用方可使用的最高版本号。高位字节指出副版本(修正)号,低位字节指明主版本号。lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节。

编辑本段注释

本函数必须是应用程序或DLL调用的第一个Windows Sockets函数。它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows

Sockets实现的细节。应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。

为支持日后可能和Windows Sockets 1.1有功能上差异的Windows Sockets实现及应用程序,在WSAStartup()中规定了一个协议。WSAStartup()的调用方和Windows Sockets DLL互相通知对方它们可以支持的最高版本,并且互相确认对方的最高版本是可接受的。在WSAStartup()函数的入口,Windows Sockets DLL检查了应用程序所需的版本。如果所需版本低于DLL支持的最高版本,则调用成功并且DLL在wHighVersion中返回它所支持的最高版本,在 wVersion中返回它的高版本和wVersionRequested中的较小者。然后Windows Sockets DLL就会假设应用程序将使用wVersion.如果WSDATA结构中的wVersion域对调用方来说不可接收,它就应调用WSACleanup()函数并且要么去另一个Windows Sockets DLL中搜索,要么初始化失败。

本协议允许Windows Sockets DLL和Windows Sockets应用程序共同支持一定范围的Windows Sockets版本。如果版本范围有重叠,应用程序就可以成功地使用Windows Sockets DLL。下列的图表给出了WSAStartup()在不同的应用程序和Windows Sockets DLL版本中是如何工作的:

应用程序版本 DLL版本 wVersionRequested wVersion wHighVersion 最终结果

1.1 1.1 1.1 1.1 1.1 use 1.1

1.0 1.1 1.0 1.1 1.0 1.0 use 1.0 1.0 1.0 1.1 1.0 1.0 1.1 use 1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1 1.1 1.0 1.1 1.0 1.0 失败

1.0 1.1 1.0 -- -- WSAVERNOTSUPPORTED 1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1 1.1 2.0 2.0 1.1 1.1 use 1.1 2.0 1.1 2.0 1.1 1.1 失败

下列代码段给出了只支持Windows Sockets 1.1版本的应用程序是如何进行WSAStartup()调用的: WORD wVersionRequested; WSADATA wsaData; int err;

wVersionRequested = MAKEWORD( 1, 1 );

err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) {

/* Tell the user that we couldn't find a useable */ /* winsock.dll. */ return; }

/* Confirm that the Windows Sockets DLL supports 1.1.*/ /* Note that if the DLL supports versions greater */ /* than 1.1 in addition to 1.1, it will still return */ /* 1.1 in wVersion since that is the version we */ /* requested. */

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {

/* Tell the user that we couldn't find a useable */ /* winsock.dll. */ WSACleanup( ); return; }

/* The Windows Sockets DLL is acceptable. Proceed. */

下面的代码段示例了只支持1.1版的Windows Sockets DLL是如何进行WSAStartup()协商的:

/* Make sure that the version requested is >= 1.1. */ /* The low byte is the major version and the high */ /* byte is the minor version. */

if ( LOBYTE( wVersionRequested ) < 1 || ( LOBYTE( wVersionRequested ) == 1 && HIBYTE( wVersionRequested ) < 1 )

{

return WSAVERNOTSUPPORTED; }

/* Since we only support 1.1, set both wVersion and */ /* wHighVersion to 1.1. */

lpWsaData->wVersion = MAKEWORD( 1, 1 );

lpWsaData->wHighVersion = MAKEWORD( 1, 1 );

一旦应用程序或DLL进行了一次成功的WSAStartup()调用,它就可以继续进行其它所需的Windows Sockets API调用。当它完成了使用该Windows Sockets DLL的服务后,应用程序或DLL必须调用WSACleanup()以允许Windows Sockets DLL释放任何该应用程序的资源。

实际的Windows Sockets实现细节在WSAData结构中描述如下: struct WSAData { WORD wVersion;

WORD wHighVersion;

char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYSSTATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; };

编辑本段成员

本函数必须是应用程序或DLL调用的第一个Windows Sockets函数。它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节。应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。

为支持日后可能和Windows Sockets 1.1有功能上差异的Windows Sockets实现及应用程序,在WSAStartup()中规定了一个协议。WSAStartup()的调用方和Windows Sockets DLL互相通知对方它们可以支持的最高版本,并且互相确认对方的最高版本是可接受的。在WSAStartup()函数的入口,

Windows Sockets DLL检查了应用程序所需的版本。如果版本高于DLL支持的最低版本,则调用成功并且DLL在wHighVersion中返回它所支持的最高版本,在

wVersion中返回它的高版本和wVersionRequested中的较小者。然后Windows Sockets DLL就会假设应用程序将使用wVersion.如果WSDATA结构中的wVersion域对调用方来说不可接收,它就应调用WSACleanup()函数并且要么去另一个Windows Sockets DLL中搜索,要么初始化失败。

本协议允许Windows Sockets DLL和Windows Sockets应用程序共同支持一定范围的Windows Sockets版本。如果版本范围有重叠,应用程序就可以成功地使用Windows Sockets DLL。下列的图表给出了WSAStartup()在不同的应用程序和Windows Sockets DLL版本中是如何工作的:

应用程序版本 DLL版本 wVersionRequested wVersion wHighVersion 最终结果

1.1 1.1 1.1 1.1 1.1 use 1.1

1.0 1.1 1.0 1.1 1.0 1.0 use 1.0 1.0 1.0 1.1 1.0 1.0 1.1 use 1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1 1.1 1.0 1.1 1.0 1.0 失败

1.0 1.1 1.0 -- -- WSAVERNOTSUPPORTED 1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1 1.1 2.0 1.1 2.0 1.1 1.1 use 1.1 2.0 1.1 2.0 1.1 1.1 失败

下列代码段给出了只支持Windows Sockets 1.1版本的应用程序是如何进行WSAStartup()调用的: WORD wVersionRequested; WSADATA wsaData; int err;

wVersionRequested = MAKEWORD( 1, 1 );

err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) {

/* Tell the user that we couldn't find a useable */ /* winsock.dll. */ return; }

/* Confirm that the Windows Sockets DLL supports 1.1.*/ /* Note that if the DLL supports versions greater */ /* than 1.1 in addition to 1.1, it will still return */ /* 1.1 in wVersion since that is the version we */ /* requested. */

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {

/* Tell the user that we couldn't find a useable */ /* winsock.dll. */ WSACleanup( );

return; }

/* The Windows Sockets DLL is acceptable. Proceed. */

下面的代码段示例了只支持1.1版的Windows Sockets DLL是如何进行WSAStartup()协商的:

/* Make sure that the version requested is >= 1.1. */ /* The low byte is the major version and the high */ /* byte is the minor version. */

if ( LOBYTE( wVersionRequested ) < 1 || ( LOBYTE( wVersionRequested ) == 1 && HIBYTE( wVersionRequested ) < 1 ) { return WSAVERNOTSUPPORTED; }

/* Since we only support 1.1, set both wVersion and */ /* wHighVersion to 1.1. */

lpWsaData->wVersion = MAKEWORD( 1, 1 );

lpWsaData->wHighVersion = MAKEWORD( 1, 1 );

一旦应用程序或DLL进行了一次成功的WSAStartup()调用,它就可以继续进行其它所需的Windows Sockets API调用。当它完成了使用该Windows Sockets DLL的服务后,应用程序或DLL必须调用WSACleanup()以允许Windows Sockets DLL释放任何该应用程序的资源。

实际的Windows Sockets实现细节在WSAData结构中描述如下: struct WSAData { WORD wVersion;

WORD wHighVersion; char

szDescription[WSADESCRIPTION_LEN+1];

char szSystemStatus[WSASYSSTATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; };

编辑本段返回值

0 成功。

否则返回下列的错误代码之一。注意通常依靠应用程序调用WSAGetLastError()机制获得的错误代码是不能使用的,因为Windows Sockets DLL可能没有建立“上一错误”信息储存的客户数据区域。 关于Windows Sockets提供者的说明:

每一个Windows Sockets应用程序必须在进行其它Windows Sockets API调用前进行WSAStartup()调用。这样,本函数就可以用于初始化的目的。 进一步的说明在WSACleanup()的说明中有讨论。

编辑本段错误代码

WSASYSNOTREADY 指出网络通信依赖的网络子系统还没有准备好。

WSAVERNOTSUPPORTED 所需的Windows Sockets API的版本未由特定的Windows Sockets实现提供。

WSAEINVAL 应用程序指出的Windows Sockets版本不被该DLL支持。

WSAStartup函数的使用

int WSAStartup( __in WORD wVersionRequested, __out LPWSADATA lpWSAData ); WSAStartup

格 式: int PASCAL FAR WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData );

参 数: wVersionRequested 欲使用的 Windows Sockets API 版本

lpWSAData 指向 WSADATA 资料的指标

传回值: 成功 – 0

失败 - WSASYSNOTREADY / WSAVERNOTSUPPORTED / WSAEINVAL

说明: 此函式「必须」是应用程式呼叫到 Windows Sockets DLL 函式中的第一个,也唯有此函式呼叫成功後,才可以再呼叫其他 Windows Sockets DLL 的函式。此函式亦让使用者可以指定要使用的 Windows Sockets API 版本,及获取设计者的一些资讯。程式中我们要用 Winsock 1.1,所以我们在程式中有一段为:

WSAStartup((WORD)((1<<8)|1),(LPWSADATA) &WSAData)

其中 ((WORD)((1<<8)|1) 表示我们要用的是 Winsock 「1.1」版本,而WSAData 则是用来储存由系统传回的一些有关此一 Winsock Stack 的资料。

The WSAStartup function initiates use of the Winsock DLL by a process.

在使用WSAStartup的使用出现了下面的问题:

源码:

#include \"stdafx.h\" #include

int main() {

WSADATA wsa={0};

WSAStartup(MAKEWORD(2,2),&wsa);

return 0; }

出现的错误信息:

错误 1 error LNK2019: 无法解析的外部符号 _WSAStartup@8,该符号在函数 _main 中被引用 CompletePortDemo.obj CompletePortDemo 解决方法:添加#pragma comment(lib,\"ws2_32.lib\") 正确代码:

#include \"stdafx.h\" #include

#pragma comment(lib,\"ws2_32.lib\")

int main()

{

WSADATA wsa={0};

WSAStartup(MAKEWORD(2,2),&wsa);

return 0; }

MAKEWORD

MAKEWORD 宏 平台:SDK

这个宏创建一个被指定变量连接而成的WORD变量。返回一个WORD变量。 (注:typedef unsigned short WORD;) WORD MAKEWORD(

BYTE bLow, //指定新变量的低字节序; BYTE bHigh //指定新变量的高字节序; );

例如:

WORD wVersionRequested;

wVersionRequested = MAKEWORD( 2, 2 );

#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) makeword是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)

makelparam、makelong和makewparam都是一样的,将两个word型合并成一个dword型。一个在高16位,一个在低16位

delphi:word((byte(a)) or (word(byte(b))) shl 8); 比如a=2;b=1

2的二进制是00000010 1的二进制为00000001 B是表示高8位,A表示低8位 合并起来就是 100000010

MAKEWORE(1,1)和MAKEWORD(2,2)的区别在于,前者只能一次接收一次,不能马上发送,而后者能。 比如:

#include #include using namespace std; int main() {

WORD wVersionRequested;

wVersionRequested=MAKEWORD(2,2);

cout << wVersionRequested << endl; return 0; }

输出的结果是514,说明是将前面的2和后面的2组成一个新的WORD。即0000 0010 0000 0010

而这个结果正是:512 + 2 = 514.

Socket接口

刘安战 发表于 - 2006-8-8 11:33:00

Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发

TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。

Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,

就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。

Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后 的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket

(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接

的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

Socket建立 为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket 函数原型为:

int socket(int domain, int type, int protocol); domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指

定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许

程序使用低层协议;protocol通常赋值\"0\"。Socket()调用返回一个整型socket描述符,你可以在后面 的调用使用它。

Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调

用Socket函数时,

socket执行体将建立一个Socket,实际上\"建立一个Socket\"意味着为一个Socket数据结构分配存储空间。

Socket执行体为你管理描述符表。

两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端

主机地址和远端协议端口。Socket数据结构中包含这五种信息。

Socket配置

通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。

面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket

的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。

Bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。Bind函数原型为:

int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信

息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。 struct sockaddr结构类型是用来保存socket信息的: struct sockaddr { unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data[14]; /* 14 字节的协议地址 */ };

sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和 端口号。

另外还有一种结构类型: struct sockaddr_in { short int sin_family; /* 地址族 */

unsigned short int sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP地址 */

unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */ };

这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,

可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相

互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向

sockaddr_in的指针转换为指向sockaddr的指针;或者相反。

使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口 号:

my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */ 通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将

my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。 注意在使用bind函数是需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_addr则不需要转 换。

计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节

优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数

据时就需要进行转换,否则就会出现数据不一致。 下面是几个字节顺序转换函数:

·htonl():把32位值从主机字节序转换成网络字节序 ·htons():把16位值从主机字节序转换成网络字节序 ·ntohl():把32位值从网络字节序转换成主机字节序 ·ntohs():把16位值从网络字节序转换成主机字节序

Bind()函数在成功被调用时返回0;出现错误时返回\"-1\"并将errno置为相应的错误号。需要注意的 是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择 大于1024中的任何一个没有被占用的端口号。

连接建立

面向连接的客户程序使用Connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为:

int connect(int sockfd, struct sockaddr *serv_addr,int addrlen); Sockfd是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是

远端地质结构的长度。Connect函数在出现错误时返回-1,并且设置errno为相应的错误码。进行客户端程

序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立

连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时 候到打断口。

Connect函数启动和远端主机的直接连接。只有面向连接的客户程序使用socket时才需要将此socket与 远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,它只是被动的在

协议端口监听客户的请求。

Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求

保存在此队列中,直到程序处理它们。

int listen(int sockfd, int backlog);

Sockfd是Socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连

接请求将在队列中等待accept()它们(参考下文)。Backlog对队列中等待服务的请求的数目进行了限制,

大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收 到一个出错信息。

当出现错误时listen函数返回-1,并置相应的errno错误码。 accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后 睡眠并等待客户的连接请求。

int accept(int sockfd, void *addr, int *addrlen); sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出

连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为

sizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数返回-1并置相应的errno值。 首先,当accept函数监视的socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这

个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的 socket上监听, 同时可以在新的socket描述符上进行数据传输操作。

数据传输 Send()和recv()这两个函数用于面向连接的socket上进行数据传输。 Send()函数原型为: int send(int sockfd, const void *msg, int len, int flags); Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据

的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。 Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回

值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。

char *msg = \"Hello!\"; int len, bytes_sent; „„

len = strlen(msg);

bytes_sent = send(sockfd, msg,len,0); „„

recv()函数原型为:

int recv(int sockfd,void *buf,int len,unsigned int flags);

Sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。

Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。

Sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器

建立连接,所以在发送数据时应指明目的地址。 sendto()函数原型为:

int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen); 该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为

sizeof (struct sockaddr)。Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。 Recvfrom()函数原型为:

int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为 sizeof (struct sockaddr)。当recvfrom()返回时,fromlen包含实际存入from中的数据字节数。

Recvfrom()函数返回接收到的字节数或当出现错误时返回-1,并置相应的errno。

如果你对数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket 仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和 源地址信息。

结束传输 当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任 何数据操作: close(sockfd);

你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而

一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直 至读入所有数据。

int shutdown(int sockfd,int how);

Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:

·0-------不允许继续接收数据 ·1-------不允许继续发送数据 ·2-------不允许继续发送和接收数据, ·均为允许则调用close ()

shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。

面向连接的Socket实例

代码实例中的服务器通过socket连接向客户端发送字符串\"Hello, you are connected!\"。只要在服务

器上运行该服务器软件,在客户端运行客户软件,客户端就会收到该字符串。 该服务器软件代码如下: #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude

#define SERVPORT 3333 /*服务器监听端口号 */ #define BACKLOG 10 /* 最大同时连接请求数 */ main() {

int sockfd,client_fd; /*sock_fd:监听socket;client_fd:数据传输socket */

struct sockaddr_in my_addr; /* 本机地址信息 */

struct sockaddr_in remote_addr; /* 客户端地址信息 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror(\"socket创建出错!\"); exit(1); } my_addr.sin_family=AF_INET; my_addr.sin_port=htons(SERVPORT); my_addr.sin_addr.s_addr = INADDR_ANY; bzero(&(my_addr.sin_zero),8); if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))

== -1) {

perror(\"bind出错!\"); exit(1); }

if (listen(sockfd, BACKLOG) == -1) { perror(\"listen出错!\");

exit(1); }

while(1) {

sin_size = sizeof(struct sockaddr_in);

if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr,

&sin_size)) == -1) { perror(\"accept出错\"); continue; }

printf(\"received a connection from %sn\n_addr));

if (!fork()) { /* 子进程代码段 */

if (send(client_fd, \"Hello, you are connected!n\ perror(\"send出错!\"); close(client_fd); exit(0); }

close(client_fd); } } }

服务器的工作流程是这样的:首先调用socket函数创建一个Socket,然后调用bind函数将其与 本机地址以及一个本地端口号绑定,然后调用listen在相应的socket上监听,当accpet接收到一个

连接服务请求时,将生成一个新的socket。服务器显示该客户机的IP地址,并通过新的socket向客

户端发送字符串\"Hello,you are connected!\"。最后关闭该socket。

代码实例中的fork()函数生成一个子进程来处理数据传输部分,fork()语句对于子进程返回的

值为0。所以包含fork函数的if语句是子进程代码部分,它与if语句后面的父进程代码部分是并发执 行的。

客户端程序代码如下: #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude

#define SERVPORT 3333

#define MAXDATASIZE 100 /*每次最大数据传输量 */ main(int argc, char *argv[]){ int sockfd, recvbytes; char buf[MAXDATASIZE]; struct hostent *host;

struct sockaddr_in serv_addr; if (argc < 2) {

fprintf(stderr,\"Please enter the server's hostname!n\"); exit(1); }

if((host=gethostbyname(argv[1]))==NULL) { herror(\"gethostbyname出错!\"); exit(1); }

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ perror(\"socket创建出错!\"); exit(1); }

serv_addr.sin_family=AF_INET;

serv_addr.sin_port=htons(SERVPORT); serv_addr.sin_addr = *((struct in_addr *)host->h_addr); bzero(&(serv_addr.sin_zero),8); if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) { perror(\"connect出错!\"); exit(1); }

if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) { perror(\"recv出错!\"); exit(1); } buf[recvbytes] = '

send()

简述:

向一个已连接的套接口发送数据。 #include

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

s:一个用于标识已连接套接口的描述字。 buf:包含待发送数据的缓冲区。 len:缓冲区中数据的长度。 flags:调用执行方式。 注释:

send()适用于已连接的数据报或流式套接口发送数据。对于数据报类套接口,必需注意发送数据长度不应超过通讯子网的IP包最大长度。IP包最大长度在WSAStartup()调用返回的WSAData的iMaxUdpDg元素中。如果数据太长无法自动通过下层协议,则返回WSAEMSGSIZE错误,数据不会被发送。

请注意成功地完成send()调用并不意味着数据传送到达。

如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞I/O方式,否则send()将阻塞。对于非阻塞SOCK_STREAM类型的套接口,实际写的数据数目可能在1到所需大小之间,其值取决于本地和远端主机的缓冲区大小。可用select()调用来确定何时能够进一步发送数据。

在相关套接口的选项之上,还可通过标志位flag来影响函数的执行方式。也就是说,本函数的语义既取决于套接口的选项也取决于标志位。后者由以下一些值组成: 值 意义

MSG_DONTROUTE 指明数据不选径。一个WINDOWS套接口供应商可以忽略此标志;MSG_OOB 发送带外数据(仅适用于SO_STREAM;)。 返回值:

若无错误发生,send()返回所发送数据的总数(请注意这个数字可能小于len中所规定的大小)。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。 错误代码:

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。 WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。 WSAEACESS:要求地址为广播地址,但相关标志未能正确设置。

WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。 WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。 WSAEFAULT:buf参数不在用户地址空间中的有效位置。

WSAENETRESET:由于WINDOWS套接口实现放弃了连接,故该连接必需被复位。 WSAENOBUFS:WINDOWS套接口实现报告一个缓冲区死锁。 WSAENOTCONN:套接口未被连接。

WSAENOTSOCK:描述字不是一个套接口。

WSAEOPNOTSUPP:已设置了MSG_OOB,但套接口非SOCK_STREAM类型。 WSAESHUTDOWN:套接口已被关闭。一个套接口以1或2的how参数调用

shutdown()关闭后,无法再用sned()函数。 WSAEWOULDBLOCK:

WSAEMSGSIZE:套接口为SOCK_DGRAM类型,且数据报大于WINDOWS套接口实现所支持的最大值。

WSAEINVAL:套接口未用bind()捆绑。

WSAECONNABORTED:由于超时或其他原因引起虚电路的中断。 WSAECONNRESET:虚电路被远端复位。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- haog.cn 版权所有 赣ICP备2024042798号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务