当前位置:  技术问答>linux和unix

Linux应用程序之socket网络编程

    来源: 互联网  发布时间:2017-05-24

    本文导语:  网络编程—服务器/客户机                                              1、 计算机网络体系结构模式 所有的网络通信方式分为两种:线路交换和包交换;线路交换是在数据传输时,在发送 端和...

网络编程—服务器/客户机                                             
1、 计算机网络体系结构模式
所有的网络通信方式分为两种:线路交换和包交换;线路交换是在数据传输时,在发送
端和接受端建立一条特定的线路连接,数据就在这条线路上传输,电话就是采用这种方式。
计算机网络则采用的是包交换的方式,数据的发送端将要发送的数据分为块,每个数据块经过处理形成一个数据包,其中包括有接受端的地址等信息,每个包都是单独传输。
2、 服务器端软件设计算法
⑴面向连接的服务器算法
① 服务器接受客户端的连接请求;
② 通过这个连接进行相关的通信;
③ 服务器在完成交互后关闭请求。
面向连接的设计方法要求每个连接都要创建一个套接口(socket),这样当请求客户过多
的时候,服务器可能因为资源耗尽而停止运行。
⑵无连接的服务器算法
无连接的设计方法中,一个套接口可以与多个主机通信,不会出现资源耗尽的问题。但是它的可靠性相对而言较差。
⑶迭代服务器的算法
在一个时刻只能处理一个客户请求的服务器叫做迭代服务器
① 创建一个套接口,并将它绑定在众所周知的服务器端口上;
② 从套接口上取下一个连接请求,并获得该请求的套接字
③ 重复读取请求队列中的连接请求,构造一个响应,按照响应的协议向客户发回响应
④ 当与特定的客户完成交互之后关闭连接,并接受新的连接请求。
⑷并发服务器的算法
并发服务器就是就是同一时刻可以处理多个客户请求的服务器。大多数的并发服务器使
用多进程来实现并发性,一个主进程最先开始运行,使用套接口在众所周知的端口监听连接
请求,并为每一个请求创建一个服务器进程,由一个从进程来处理一个客服的通信。
① 创建UDP套接口并与众所周知的端口绑定;
② 调用recefrom()来接受客户端的请求,并创建一个新的进程来处理响应;


3、 socket基础
socket接口是TCP/IP网路的API,socket接口定义了许多函数或者例程,程序员可以
用它们来开发网络应用程序。网络socket数据传输是一种特殊的I/O,socket也是一种文件
描述符。Socket也具有一个类似打开文件的函数调用socket(),该函数返回一个socket
文件描述符句柄。随后连接的建立,数据的传输等操作都是通过该句柄来实现的。
⑴套接字的基本类型
① 数据流套接字(SOCK_STREAM):数据流套接字是一种面向连接的套接字,采用的面
向连接的TCP服务应用。Eg telnet 、www浏览器使用的Http协议
② 数据报套接字(DGRAM):数据报套接字是一种无连接的套接字,对应于无连接的UDP
服务应用。
4、socket网络编程
Linux采用了socket套接字,与套接字相关的函数包含在头文件sys/socket.h中。
Socket相当网络上的通信节点,即IP和端口号组成。
网络程序的设计可以采用TCP和UDP两种协议,TCP是一种可靠的、面向连接的协
议,而UDP是一种不可靠的无连接的协议。 
4.1采用TCP协议进行网络程序设计
⑴在进行网络程序设计的时候,一般按照客户端和服务器端分别进行设计,其设计流程
是不一样的,下图为TCP网络程序设计的设计流程。
   
Linux应用程序之socket网络编程[图片]
 
图4-1 TCP程序设计流程
⑵ socket相关的函数
①socket()函数
表头文件 #include 
定义函数: int socket(int family,int type,intprotocol);
函数说明: socket() 函数用来生成一个套接口描述字,也称为套接字,指定协议族和套接口。参数: family 指定协议族(在网络程序中只能设置为:AF_INET), type 指明套接字的类型(SOCK_STREAM为数据流套接字,采用TCP建立连接,而SOCK_DGRAM数据报套接字,采用的是UDP协议),而 protocol 一般为 0
③ bind()函数
表头文件 #include  #include
定义函数 int bind(int sockfd, (struct sockaddr *) my_addr, int addrlen);
函数说明 bind() 用于将本机的地址与创建的套接字绑定。其中sockfd为套接字号,
my_addr为指向地址结构的指针,addrlen为地址结构sockaddr_in的长度。成功返回0,失
败返回-1,把错误原因放在在errno中。
与套接字绑定的地址因为协议族的不同(family)而不同,在网络程序中因为family只能取AF_INET,故sockaddr的结构定义为:
struct sockaddr_in{
sa_family_t sin_family;
unsigned short int sin_port;/*端口号*/
struct in_addr sin_addr;    /*IP地址*/
}
struct in_addr
{
uint32_t s_addr;
};
由于IP地址为xx.xx.xx.xx的字符形式地址结构体中的IP地址为无符号整型,因此需要
采用下面的函数进行转换:
unsigned long inet_addr(const char * string);
而端口号的获取需要使用下面的两个函数,因为一般intel架构的处理器采用的是小端格式,而motorola和sun公司的机器采用的是大端格式,为了消除这个差别,必须采用下面的两个函数设置端口号;
unsigned long htonl(unsigned long  hostlong);
unsigned long htons(unsigned long  hostshort);
eg  struct sockaddr_in adr_srvr;
adr_srvr.sin_addr.s_addr=inet_addr(“192.168.1.105”);
    adr_srvr.sin_port=htons(8000);
④ listen()函数
头文件:#include
函数原型:int listen(int sockfd, int backlog);
在套接字创建之后,它是一个主动连接的套接字,也就是此时系统假设用户会对这个套
接字调用connect函数,期待它主动与其它进程连接,然而在服务器编程中,用户希望这
个套接字可以接受外来的连接请求,也就是被动等待用户来连接。因此需要通过listen()
函数来使主动套接口变为被动套接口,从而使得一个进程可以接受其它进程的连接请求变为
服务器进程; 参数backlog用来指定最大的连接数,一般设定为5;
⑤accept()函数
头文件:#include
函数原型:int accept(int sockfd, struct sockaddr_in *addr, int addrlen);
当服务器端接受到客户端的连接请求的时候,会把连接请求方在连接队列中,接着用
accept()函数处理并接受队列中的请求。accept默认会阻塞进程,直到有一个客户连接
建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。"阻塞"是一个术
语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;
通常"阻塞"是由循环产生的。此时我们需要区分两种套接字,一种套接字正如
accept的参数sockfd,它是监听套接字,在调用listen函数之后,一个套接字
会从主动连接的套接字变身为一个监听套接字;而accept返回是一个连接套接字,
它代表着一个网络已经存在的点点连接。
参数sockfd:
参数sockfd就是上面解释中的监听套接字,这个套接字用来监听一个端口,当有一个
客户与服务器连接时,它使用这个一个端口号,而此时这个端口号正与这个套接字关联。
当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
参数addr:
这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地
址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地
址不感兴趣,那么可以把这个值设置为NULL。
参数len:
如同大家所认为的,它也是结果的参数,用来接受上述addr的结构的大小的,它指明
addr结构所占有的字节个数。同样的,它也可以被设置为NULL。如果accept成功返回,
则服务器与客户已经正确建立连接了,此时服务器通过accept返回的套接字来完成与客户
的通信。

 
⑥connect()函数
头文件:#include
函数原型:int connect(int sockfd,struct sockaddr *addr,int addrlen);
  connect函数是客户端使用的函数,当用创建一个套接口后,可以调用connect为这
个套接字指明远程端的地址;如果是字节流套接口,connect就使用三次握手建立一个连
接;如果是数据报套接口,connect仅指明远程端地址,而不向它发送任何数据。第一个
参数是socket函数返回的套接口描述字(套接字);第二和第三个参数分别是一个指向服
务器端套接口地址结构的指针和该结构的大小。
这些地址结构的名字均已“sockaddr_”开头,并以对应每个协议族的唯一后缀结束。
以IPv4套接口地址结构为例,它以“sockaddr_in”命名,定义在头文件;
以下是结构体的内容:
struct in_addr { 
in_addr_t s_addr;/* IPv4地址 */
};
struct sockaddr_in { 
uint8_t sin_len; /* 无符号的8位整数 */
sa_family_t sin_family;
/* 套接口地址结构的地址簇,这里为AF_INET */
in_port_t sin_port; /* TCP或UDP端口 */
struct in_addr  sin_addr; 
char sin_zero[8]; 
};
⑦ send()函数
头文件:#include
函数原型:int send(int sockfd, const char *buf,  int len,  int flags);
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客
户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发
送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用程序
要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。
同步Socket的send函数的执行流程:
(1)send先比较待发送数据的长度len和套接字的发送缓冲的长度,该函数返回SOCKET_ERROR;
(2)如果len小于或者等于套接字的发送缓冲区的长度,那么send先检查协议是否
正在发送套接字发送缓冲区中的数据,如果是就等待协议把数据发送完,如果协议还没有开
始发送套接字发送缓冲区中的数据或者套接字发送缓冲区中没有数据,那么send就比较套
接字的发送缓冲区的剩余空间和len的大小;
(3)如果len大于剩余空间大小,send就一直等待协议把套接字发送缓冲中的数据发送完
(4)如果len小于剩余空间大小,send就仅仅把buf中的数据copy到剩余空间里
(注意并不是send把套接字发送缓冲区中的数据传到连接的另一端的,而是协议传的,s
end仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。
如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数
据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时
网络断开的话,那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的
数据成功copy到套接字发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定
马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个S
ocket函数就会返回SOCKET_ERROR。
注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
⑧recv()函数
头文件:#include
函数原型:int recv(int sockfd, const char FAR*buf, int len, int flags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数
的第一个参数指定接收端套接字描述符;第二个参数指明一个缓冲区,该缓冲区用来存放r
ecv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。
同步Socket的recv函数的执行流程:
(1)recv先等待套接字发送缓冲区中的数据被协议传送完毕,如果协议在传送套接字
发送缓冲区中数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
(2)如果套接字的发送缓冲区中没有数据或者数据被协议成功发送完毕后,recv先检
查套接字的接收缓冲区,如果套接字接收缓冲区中没有数据或者协议正在接收数据,那么
recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把套
接字的接收缓冲区中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,
所以 在这种情况下要调用几次recv函数才能把套接字的接收缓冲中的数据copy完。rec
v函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy
的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在
等待协议接收数据时网络中断了,那么它返回0。
注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
⑨ close()函数
头文件:#include
函数原型:int close(int sockfd);
使用close()函数终止客户端和服务器端的连接,函数运行成功返回0,否则返回-1.
5、socket 聊天工具
5.1 服务器端的源码:
/*server program*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXBUF 1024
int main(int argc,char *argv[])
{
  int sockfd,new_fd;
  char buffer[MAXBUF+1];
  socklen_t len;
  struct sockaddr_in my_addr,their_addr;
  struct sockaddr my_addr1 ,their_addr1;
 /*create socket */
  sockfd=socket(AF_INET,SOCK_STREAM,0);
  if(sockfd==(-1))
    {
      printf("create socket fail!");
      exit(1);
    }
  /*bind the ipv4 and socket*/
  my_addr.sin_family=AF_INET;
  my_addr.sin_port=htons(7838); /*use the port 7838*/
  my_addr.sin_addr.s_addr=INADDR_ANY;
  if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==(-1))
    {
      perror("bind");
      exit(1);
    }
   /*monitor the customers request*/
  if(listen(sockfd,5)==(-1))
  {
    perror("listen");
    exit(1);
  }
  while(1)
  {
    printf("---------------------The server start-----------------n ");
    len=sizeof(struct sockaddr);
    new_fd=accept(sockfd,(struct sockaddr *)&their_addr,&len);
    if(new_fd==-1)
    {
      perror("accept");
      exit(1);
    }
    else
    {
      printf("server:get connection from %s,port %d,socket %dn",
      inet_ntoa(their_addr.sin_addr),their_addr.sin_port,new_fd);
    }
      /*deal with  message  */
    while(1)
    {
    /*send message*/
      bzero(buffer,MAXBUF+1);
      printf("send message:");
      fgets(buffer,MAXBUF,stdin);
fgets(buffer,MAXBUF,stdin);
      if(!strncasecmp(buffer,"quit",4))
      {
        printf("Quitn");
        break;
      }
      if(len=send(new_fd,buffer,strlen(buffer)-1,0)0)
        printf("Receive message:%sn",buffer);
      else
        {
          if(len0)
{
    printf("Receive message:%sn",buffer);
}
else
{
    if(len

    
 
 

您可能感兴趣的文章:

  • 《UNIX网络编程》这本书适合linux下的网络编程吗?
  • 那里有linux c 函数库和linux 网络编程的书下载??
  • 学习Linux的网络编程,请问使用哪个公司的linux最好?
  • 请问unix网络编程和linux网络有什么区别
  • 新手请教,linux网络编程。
  • Unix/Linux网络编程怎样来做一个项目?
  • linux环境进行网络编程的教材
  • linux下网络编程环境配置问题
  • 请推荐几本Linux/Unix网络编程的好书吧
  • 求介绍linux下的网络编程书
  • 求助linux下的网络编程问题
  • 请有经验的朋友推荐一下Linux/Nnix下网络编程方面的书,急需学习
  • 求助:linux/unix网络编程
  • 帮推荐一本linux 网络编程的经典书吧
  • 会Linux下网络编程,能找到什么样的工作,从事什么?
  • Unix/Linux网络编程可以用来做什么?一般从事什么样的职业?
  • 学习linux网络编程需要学习些内核知识吗?
  • 哪里可以免费下载Linux下C网络编程方面的好书?
  • linux 网络编程的问题
  • 请教LINUX下的网络编程?
  • 怎样开发在LINUX 上运行的应用程序,像WINDOWS桌面应用程序一样
  • linux开发的应用程序部署到其他linux的问题
  • 新手提问:在REDHAT LINUX 下开发应用程序,用什么工具好,除了 LINUX C以外
  • 菜鸟求助:Linux 应用程序后台启动后关闭窗口程序退出
  • 学了linux程序设计后能不能编写出应用程序
  • 请问能否在linux实现一个应用程序访问另外一个程序的内存数据?
  • 几个Linux应用程序开发的问题请教LINUX程序员!
  • linux 桌面应用程序和web应用程序编写常用的语言
  • Linux应用程序启动器 Kupfer
  • 使用linux内核+qt开发的应用程序需要开源吗
  • linux驱动程序是怎样通过内核和应用程序通信,还有是怎样和硬件通信,跪求求解,谢谢高手留言。
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Linux c socket编程:简单的客户端(client)和服务端(server)实现
  • 都说《UNIX环境高级编程》好,对于学linux编程好不好?《Linux下的c编程》《嵌入式系统C编程》那个更适合初学者?各是那个出版社的?(
  • Linux下c/c++ boost安装及并发编程库mpi介绍
  • 我想学Linux编程,请大家推荐几本学习Linux下C/C++编程的书
  • 学Linux编程前要学Unix吗?哪里有学Linux编程的好书下载?
  • 我想学习linux桌面编程,那么有没有必要学习linux的内核以及内核的相关编程呢?
  • unix编程与linux编程有什么区别?
  • linux下编程跟平时的编程有什么区别吗?
  • Linux下的编程指的就是Shell编程吗?
  • 帮我介绍基本linux下编程的书,《Linux上的C编程》这本书怎么样?还有别的书吗?
  • Linux下使用openssl api编程socket编程,为什么要编译啊?
  • 请教linux下的编程的选择:我听说有gtk+gnome的编程,也有kde里的 什么编程,到底应该选择哪个呢?好象一个是技术好一点,一个是市场占有
  • 请问LINUX编程(内核编程)是在什么环境下用什么IDE编?
  • Linux C编程一站式学习,高级shell Bash脚本编程指南,
  • 我学&用Linux编程,手里有《UNIX环境高级编程》,看它行吗?
  • Linux下编程有哪本比较好的书可以推荐下呢。本人看过鸟哥的私房菜了,linux基本操作了解了,现在想开始学linux 下的编程 。我以后打算往网络这方面去学习
  • 都说《UNIX环境高级编程》好,对于学linux编程好不好?是那个出版社的,是中文版吗?
  • 我想学Linux编程,请大家推荐几本学习Linux下C/C++编程的书 iis7站长之家
  • 哪位编程高手知道如何编程实现获取进程的内存使用量信息(linux)
  • 初学者问题,哪里有适合入门的编程电子书看 linux 下 c编程
  • 请问linux/unix下编程与windows下编程有什么不同呢??
  • linux c/c++ IP字符串转换成可比较大小的数字
  • 在win分区上安装linux和独立分区安装linux有什么区别?可以同时安装吗?(两个linux系统)
  • linux哪个版本好?linux操作系统版本详细介绍及选择方案推荐
  • 在虚拟机上安装的linux上,能像真的linux系统一样开发linux程序么?
  • secureCRT下Linux终端汉字乱码解决方法
  • 我重装window后,把linux的引导区覆盖了,进不了linux怎么办?急啊,望热心的人帮助 (现在有linux的盘)
  • Linux c字符串中不可打印字符转换成16进制
  • 安装vmware软件,不用再安装linux系统,就可以模拟linux系统了,然后可以在其上学习一下LINUX下的基本操作 了?
  • Linux常用命令介绍:更改所属用户群组或档案属性
  • 红旗Linux主机可以通过127.0.0.1访问,但如何是连网的Win2000机器通过Linux的IP去访问Linux


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3