首页 > 学院 > 开发设计 > 正文

C语言网络编程之流式套接口编程流程

2019-11-06 07:04:38
字体:
来源:转载
供稿:网友

面向链接的C/S程序设计

服务器(Server)端程序设计

Step1:初始化WinsockStep2:创建套接字Step3:将套接字绑定到一个特定的ip和PORTStep4:将套接字设为监听模式,准备接受客户的请求Step5:准备客户机请求的到来,当客户机请求到来后,接收链接请求,返回一个新的对应于此次链接的套接字Step6:用返回的套接字和客户端进行通信Step7:返回,等待另一客户的请求Step8:关闭套接字Step9:终止使用Winsock

客户(Client)端程序设计

Step1:初始化WinsockStep2:创建套接字Step3:向服务器发出链接请求Step4:和服务器端进行通信Step5:关闭套接字Step6:终止使用Winsock

面向连接的C/S程序工作流程图(TCP

流式套接口编程流程(revised)

基本套接口函数

打开Winsock WSAStartup()创建套接口 socket()或WSA Socket()指定本地地址 bind()监听连接 listen()请求连接 connect()或WSA Connect()接收连接 accept()或WSA Accept()发送数据 send()接收数据 recv()关闭套接口 closesocket()

初始化winsock

Winsock 应用程序要做的第一件事,就是必须首先调用WSAStartup()函数对Winsock进行初始化成功后才能调用其他的Winsock API函数。

WSAStartup()函数的调用格式

  intWSAStartup(Word wVersionRequested, LPWSADATA lpWSAData)  

用法

wVersionRequested用来指定载入的winsock的版本两个主流版本winsock1.1和winsock2.2

两种方法

1.使用MAKEWORD()宏来指定版本号:MAKEWORD(x,y),x是主版本号,y是次版本号

如:MAKEWORD(2,2)

2.直接将该参数设定为0x101或0x202

WSAData:是一个指向WSAData结构的指针,WSAStartup函数会向该结构填充载入的winsock动态链接库的信息

列如
  WSADATA WsaDat  WSAStartup(MAKEWORD(2,2), &WsaDat);  

注销函数 WSACleanup()

当程序使用完Winsock.dll提供的服务后,应用程序必须调用WSACleanup()函数,来解除与Winsock.DLL库的绑定,释放Winsock实现分配给应用程序的系统资源,中止对Windows Sockets DLL的使用。
  intWSACleanup ( void ); 

创建套接口socket()

socket过程创建一个套接字并返回一个整型描述符格式:int SOCKET( intPRotofamily, intType, intProtocol); 参数1: 说明使用协议簇,对于IPv4,设置为AF_INET参数2:说明套接字类型 SOCK_STREAMSOCK_DGRAMSOCK_RAW参数3:采用的底层协议,设为0时为套接字服务自动选择套接字创建成功,则返回套接字描述符,否则返回INVALID_SOKET错误

实例:

  SOCKET sockfd=SOCKET( AF_INET, SOCK_STREAM, 0);  /* 创建一个流式套接字。  SOCKET sockfd=SOCKET( AF_INET, SOCK_DGRAM, 0);  /* 创建一个数据报套接字。

bind()绑定网络地址

多用于服务器将创建的套接字与制定的网络地址进行绑定,客户端一般不需绑定intbind( intSockfd, structsockaddr* My_addr, int Addrlen); 参数1:套接字标识符参数2:要绑定的网络地址参数3:网络地址结构的长度返回值:若返回0表示正确绑定,否则返回SOCKET_ERROR表示有错。

sockaddr_in结构,专门针对Internet通信域,存储套接字相关的网络地址信息,例如IP地址,传输层端口号等信息。

     structsockaddr_in{       short int          sin_family;    // 地址家族       unsigned short int  sin_port;    //  端口号       structin_addr     sin_addr;     // IP 地址       unsigned char     sin_zero[8];  // 全为0     }  

在建立地址时,使用sockaddr_in结构

在使用时,将sockaddr_in结构强制转换为sockaddr结构

  sockaddr_inmy_addr; //定义地址  my_addr.sin_family=AF_INET;//为地址赋值  My_addr.sin_port=htons(3000);  addr.sin_addr.s_addr=htonl(INADDR_ANY);  bind(sockfd, (SOCKADR*)&my_addr, sizeof(my_addr))//绑定  

创建套接字示例

  SOCKET serSock;        // 定义了一个SOCKET 类型的变量。  sockaddr_in my_addr;    // 定义一个Sockaddr_in型的结构实例变量。  interr;                  // 出错码。  int slen=sizeof( sockaddr);  // sockaddr结构的长度。  serSock = socket(AF_INET, SOCK_DGRAM,0 );     // 创建数据报套接字。  memset(my_addr,0);         // 将Sockaddr_in的结构实例变量清零。  my_addr.sin_family= AF_INET;             // 指定通信域是Internet。  my_addr.sin_port= htons(21);               // 指定端口,将端口号转换为网络字节顺序。  /* 指定IP地址,将IP地址转换为网络字节顺序。  my_addr.sin_addr.s_addr= htonl( INADDR-ANY);  /* 将套接字绑定到指定的网络地址,对&my_addr进行了强制类型转换。  if  (BIND(serSock, (LPSOCKADDR )&my_addr, slen) == SOCKET_ERROR )  {  /* 调用WSAGetLastError()函数,获取最近一个操作的错误代码。  err = WSAGetLastError();  /* 以下可以报错,进行错误处理。  }  

connect()连接函数

仅用于客户端,用来请求建立服务器连接格式:int connect( intsockfd, structsockaddr* name, int namelen);返回值:连接成功,返回0;否则返回-1

if (connect(sockfd, (structsockaddr*)(&serv_addr),sizeof(structsockaddr))<0)

{ 报错,并退出 }

举例

  struct sockaddr_in daddr;  memset((void *)&daddr,0,sizeof(daddr));  daddr.sin_family=AF_INET;  daddr.sin_port=htons(8888);  daddr.sin_addr.s_addr=inet_addr("133.197.22.4");  If (connect(ClientSocket,(struct sockaddr *)&daddr,sizeof(daddr))<0) { 报错,并退出 };  

listen()

告诉服务器端套接字开始监听客户机的连接请求格式:intlisten(intSocket, int backlog)Socket是已经建立的套接字backlog表示能同时处理的最大链接请求如果超过总这个数目,客户端将会接收到ECONNREFUSED拒绝链接的错误。如果socket为AF_INET则参数backlog最大可设至128,即最多可以同时接受128个客户端的请求可将该参数设置为3~5告诉服务器端套接字开始监听客户机的连接请求

格式:intlisten(intSocket, int backlog)

accept()

格式:int accept( int sockfd, structsockaddr* addr, int* addrlen);返回值:如执行正确,返回新的套接字描述符,该套接字已和请求的客户端建立连接;否则出错返回-1.举例:
  int  clientfd;                  // 定义响应套接字描述符变量  intaddrler=sizeof(sockaddr);     // 获得套接字地址结构长度。  structsockaddr_incltsockaddr;   // 定义返回客户端地址的结构  clientfd=ACCEPT(listenfd, (sockaddr* )(&cltsockaddr), &addrlen);  // 接收客户连接请求  

断开套接字shutdown()

禁止在一个套接口上进行数据的接收与发送格式:intshutdown( int sockfd, inthow) SD_SENDSD_RECEIVESD_BOTHHow取值SD_RECEIVE //不允许再对此套接口调用接收函数SD_SEND //不允许再对此套接口调用发送函数SD_BOTH //关闭通道,相当于执行了上述两个命令

关闭套接字closesocket()

关闭套接字,释放资源格式:intclosesocket( intsockfd)

send()

向一个已连接的套接字发送数据格式: int send( intsockfd, char * buf, intlen, intflags);

正确返回实际发送的字节数,否则返回-1

Winsock的信息查询函数

Gethostname()用来返回本地计算机的标准主机名。intgethostname(char* name, intnamelen);Gethostbyname()返回对应于给定主机名的主机信息。structhostent* gethostbyname(const char* name);Gethostbyaddr()根据一个IP地址取回相应的主机信息。structhostent* gethostbyaddr(constchar* addr, intlen, inttype);Getservbyname()返回对应于给定服务名和协议名的相关服务信息。structservent* getservbyname(constchar* name, constchar* proto);

实例

服务器

  // Demo_3_4.cpp : 定义控制台应用程序的入口点。  //  #include "stdafx.h"  #include <iostream>  #include "winsock2.h"  #pragma comment (lib, "ws2_32.lib")  int _tmain(int argc, _TCHAR* argv[])  {       WSADATA wsaData;      SOCKET sockfd;     if(WSAStartup(MAKEWORD(2,2),&wsaData)<0)    {      printf("WSAStartup failed/n");      return 1;    }    else  {    printf("WSAStartup successed!/n");    }    ockfd=socket(AF_INET,SOCK_STREAM,0);    if(sockfd==SOCKET_ERROR)  {     printf("套接口创建失败!");     WSACleanup();     return 1;  }  else  {   printf("a new socket has been created!/n");   printf("the socket id is %d/n",sockfd);  }  struct sockaddr_in addr;   int addr_len=sizeof(struct sockaddr_in);  addr.sin_family=AF_INET;  addr.sin_port=htons(8888);  addr.sin_addr.s_addr=INADDR_ANY;  if(bind(sockfd,(SOCKADDR *)&addr, sizeof(addr))<0)  {   printf("bind error!");   return 1;  }   else  {      printf("bind ok!");   }    listen(sockfd,1);    SOCKET TempSock=SOCKET_ERROR;    while(TempSock==SOCKET_ERROR)   {      std::cout<<"服务器:正在等待来自客户机的连接.../r/n";     TempSock=accept(sockfd,NULL,NULL);   }   sockfd=TempSock;   std::cout<<"服务器:有客户机到达!/r/n/r/n";   u_long iMode=1;    ioctlsocket(sockfd,FIONBIO,&iMode);    for(;;)   {        char *szMessage="服务器说:有朋自远方来,不亦悦乎。/r/n";        send(sockfd,szMessage,strlen(szMessage),0);        int nError=WSAGetLastError();       if(nError!=WSAEWOULDBLOCK && nError!=0)      {       std::cout<<"WinSock错误码为:"<<nError<<"/r/n";    std::cout<<"客户机断开连接。/r/n";    shutdown(sockfd,SD_SEND);    closesocket(sockfd);    break;  }  Sleep(1000);  }  WSACleanup();  return 0;  }  

客户机
 // Demo_3_3.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream>  #include "winsock2.h" #pragma comment (lib, "ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; SOCKET sockfd; if(WSAStartup(MAKEWORD(2,2),&wsaData)<0) { printf("WSAStartup failed/n"); return 1; } else   printf("WSAStartup successed!/n"); sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==SOCKET_ERROR) { printf("套接口创建失败!"); WSACleanup(); return 1; } else {  printf("a new socket has been created!/n"); printf("the socket id is %d/n",sockfd); } struct sockaddr_in addr; int addr_len=sizeof(struct sockaddr_in); addr.sin_family=AF_INET; addr.sin_port=htons(8888); addr.sin_addr.s_addr=inet_addr("10.0.0.2"); printf("the ip address of the server is: %s/n",inet_ntoa(addr.sin_addr)); if(connect(sockfd,(SOCKADDR *)&addr, sizeof(addr))<0) { printf("connect error!/n"); return 1; } else { printf("connected ok!/n"); } u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); for(;;) { char buffer[1024]; memset(buffer, 0,1023); int inDataLength=recv(sockfd, buffer,1024,0); std::cout<<buffer; int nError=WSAGetLastError(); if(nError!=WSAEWOULDBLOCK && nError!=0) { std::cout<<"WinSock错误码为:"<<nError<<"/r/n"; std::cout<<"服务器断开连接。/r/n"; shutdown(sockfd,SD_SEND); closesocket(sockfd); break; } Sleep(1000); } WSACleanup(); return 0; } 

运行结果


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表