服务器与客户端网络通信经典讲解

 服务器与客户端网络通信方式有多种,既可以使用listen,accept进行监听实现,也可以使用sendto,recvfrom来实现。现将一后者方法经典详解实例贴在这儿供大家学习。

server:

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define MAXBUF 256//定义了常量MAXBUF的值256,下面会用到.当然您也可以不用定义,在后面的数组里直接写256这个数字也可以

main()
{
 char buf[MAXBUF];//字符串数组buf的大小是256

 int passiveSocket;//定义一个int类型的变量passiveSocket,它用来存储套接字描述符

 socklen_t clientAddrLen;//类型的变量clientAddrlen,用来接收客户端地址的长度
 //定义一个sockaddr_in类型的结构变量serverAddr,用来存储服务器端的IP地址,端口等信息
 struct sockaddr_in serverAddr;
 //定义一个sockaddr_in类型的结构变量clientAddr,用来存储客户端的IP地址,端口等信息
 struct sockaddr_in clientAddr;
    //socket函数需要传递3个值: 对于使用IPV4的网络接口,第1个参数必须是AF_INET.由于是UDP传输方式,第2个参数必须是SOCK_DGRAM.对于使用TCP或者UDP的传输,第3个参数都设置为0
 passiveSocket=socket(AF_INET,SOCK_DGRAM,0);
    //初始化变量serverAddr,使其为数字0
 memset(&serverAddr,0,sizeof(serverAddr));
 //把serverAddr结构中的sin_family变量赋值为AF_INET,这个值表示TCP/IP网络
 serverAddr.sin_family=AF_INET;
 //把serverAddr结构中的sin_port变量赋值为1234,这个值代表服务器的接收端口为1234,您可以自行设置.htons函数是必须的,它把主机字节顺序转换为网络字节顺序
 serverAddr.sin_port=htons(1234);
 //设置要绑定服务器的哪个IP地址.使用INADDR_ANY可以把服务器绑定在本机的所有IP地址.也可以使用inet_addr捆绑在特定端口.因为IP地址是32位的,
 //所以需要使用htonl来转换网络字节顺序,而htons是用来转换2个字节16位的端口地址
 serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);/* serverAddr.sin_addr.s_addr = inet_addr(”127.0.0.1″); */
 //使用bind函数把刚才创建的套接字描述符passiveSocket与服务器套接字结构serverAddr捆绑在一起.
 if(bind (passiveSocket,(struct sockaddr *)&serverAddr,sizeof(serverAddr))==-1)
 printf ("bind Error!");
 clientAddrLen=sizeof(serverAddr);
 memset(buf,0,MAXBUF);//初始化buf数组,设置为数字0
    //因为是服务器端程序,需要一直打开接收来自客户端的请求,所以必须创建一个死循环
 for(;;)
 {
  //利用recvfrom函数接收来自客户端的信息,并把信息存放在数组buf中.同时也把客户端的地址存放在了clientAddr中,方便信息的回送,本例服务器端为使用回送.
  if(recvfrom(passiveSocket,buf,MAXBUF,0,(struct sockaddr *)&clientAddr,&clientAddrLen)>0)
  {
   //打印输出来buf中自客户端的信息
   printf("Come from Client is : %s/n", buf);
   memset (buf,0,sizeof(buf));//清空buf

  }
 }
}

 

client:

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
//定义了常量MAXBUF的值256,下面会用到.当然您也可以不用定义,在后面的数组里直接写256这个数字也可以
#define MAXBUF 256
main()
{
 //给buf数组赋值为Hello World,这个字符串是后面要传送给服务器的信息
 char buf[MAXBUF]="Hello World";
 //定义一个整型变量activeSocket,它用来存储套接字描述符.
 int activeSocket;
 //同server.c中注释,设置Internet套接字地址结构变量remoteAddr
 struct sockaddr_in remoteAddr;
    //同server.c中注释,设置Internet套接字地址结构变量localAddr
 struct sockaddr_in localAddr;
    //如果链接远程服务器使用URL的方式,则需定义此变量用来接收解析后的IP地址.
 struct hostent *hptr;
    //同server.c中的注释,创建一个套接字结构,成功创建后把返回的套接字描述符存储在activeSocket
 activeSocket=socket(AF_INET,SOCK_DGRAM,0);
 //同server.c中的注释
 memset(&remoteAddr,0,sizeof(remoteAddr));
 //同server.c中注释
 remoteAddr.sin_family=AF_INET;
 //设置远程服务器的端口地址
 remoteAddr.sin_port=htons(1234);
 //设置远程服务器的IP地址,本例因为服务器和客户端在同一台机器上,所以使用同一个地址.
 remoteAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
 /*hptr=gethostbyname(”www.aorb.org”);
 memcpy((char*)&remoteAddr.sin_addr.s_addr,hptr->h_addr_list[0],hptr->h_length);*/
 //如果链接远程服务器使用URL,则需要用gethostbyname函数得到预解析URL的地址储存在hptr结构中,
 //然后把hptr结构中的h_addr_list[0]值拷贝到套接字remoteAddr.sin_addr.s_addr变量. memcpy函数就是起到拷贝的作用.
 printf("Remote IP address is: %s…/n",inet_ntoa(remoteAddr.sin_addr));
 //发从存储在数组buf中的信息,也就是发送”Hello World”字符串到remoteAddr中指定的IP地址与端口.
 sendto (activeSocket,buf,sizeof(buf),0,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr));
 //如果sendto成功则显示Send Success!
 printf("Send Success!/n");
 memset (buf,0,sizeof(buf));//重置buf数组
 close(activeSocket);//关闭activeSocket套接字释放内存.
}
//在UNIX系统中,进程若对文件进行操作,一般使用open函数调用打开一个文件进行访问,每个进程都有一个文件描述符表,
//该表中存放了被进程打开的文件的索引(也称文件描述符),索引指出了文件在文件描述符表中的位置,
//这个索引值是一个指向操作系统文件表的指针.应用程序只要使用该描述符就可以对指定文件进行操作.类似的,
//每个打开的socket函数都对应一个整数,我们称它为socket描述符,该整数也是socket描述符在文件描述符表中的索引值.
//但socket描述符在描述符表中的表项并不指向文件表,而是指向一个与该socket有关的数据结构– socket结构.
//    当程序用open函数打开一文件描述符,文件描述符指向一个文件表,而这个表指向文件在硬盘的具体位置.类似的,
//当程序用socket函数创建一个socket结构,但这个结构并不完整,需要使用send或者recvfrom等函数向socket结构填写其他部分,
//以指明预访问的目的地址或接收到的源地址.

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值