天天看点

linux socket通信

通过使用SOCKET可以完成不同计算机间的进程通信。两台计算机可以位于任意位置通过使用SOCKET

进行通信和消息交互。

int   socket(intdomain,inttype,intprotocol);

第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;

第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部);

第三个参数指定应用程序所使用的通信协议。此参数可以指定单个协议系列中的不同传输协议。在Internet通讯域中,此参数一般取值为0,系统会根据套接字的类型决定应使用的传输层协议。

INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。

bind函数用于将套接字与指定端口相连,其具体信息如表13.4所示。

表13.4   bind函数

头文件

<sys/types.h>

<sys/socket.h>

函数形式 int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
返回值 成功 失败 是否设置errno
1

说明:

当调用socket函数创建套接字后,该套接字并没有与本机地址和端口等信息相连,bind函数将完成这些工作。bind函数中的sockfd参数为调用socket函数后返回的文件描述符。my_addr参数为指向sockaddr结构体的指针(该结构体中保存有端口和IP地址信息)。addlen参数为结构体sockaddr的长度。

int listen(SOCKET sockfd, int backlog)

listen函数使用主动连接套接字变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

listen函数一般在调用bind之后-调用accept之前调用。

fd_set

select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件发生了可读或可写事件。

FD_ZERO(&set);                 /*将set清零使集合中不含任何fd*/

FD_SET(fd, &set);               /*将fd加入set集合*/

FD_CLR(fd, &set);               /*将fd从set集合中清除*/

FD_ISSET(fd, &set);            /*在调用select()函数后,用FD_ISSET来检测fd在fdset集合中的状态是否变化返回整型,当检测到fd状态发生变化时返回真,否则,返回假(0)*/

select

select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他 文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执 行了select()的进程哪一Socket或文件可读。

accept函数

处于监听状态的服务器在获得客户机的连接请求后,会将其放置在等待队列中。当系统空闲时,将接受客户机的连接请求。接收客户机的连接请求使用accept函数,该函数的具体信息如表13.6所示。

表13.6   accept函数

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回新的套接字文件描述符

accept函数用于面向连接类型的套接字类型(SOCK_STREAM和SOCK_SEQPACKET)。accept函数将从连接请求队列中获得连接信息,创建新的套接字,并返回该套接字的文件描述符。新创建的套接字用于服务器与客户机的通信,而原来的套接字仍然处于监听状态。

accept函数的sockfd参数为监听的套接字描述符。addr参数为指向结构体sockaddr的指针。参数addrlen为addr参数指向的内存空间的长度。

服务器程序

#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<sys/time.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  int server_socket,client_socket;
  int server_len,clinet_len;
  struct sockaddr_in server_address;
  struct sockaddr_in client_address;
  int iResult;
  fd_set readfds,testfds;
  //建立服务器端SOCKET
  server_socket = socket(AF_INET,SOCK_STREAM,0);
         
  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = htonl(INADDR_ANY);
  server_address.sin_port = htons(9734);
  server_len = sizeof(server_address);
  //将服务器端的SOCKET与端口和IP绑定
  bind(server_socket,(struct sockaddr *)&server_address,server_len);
  //在服务器端监听客户请求
  listen(server_socket,5);
         
  FD_ZERO(&readfds);
  FD_SET(server_socket,&readfds);
         
  while(1)
  {
      char ch;
      int fd;
      int nread;
             
      testfds = readfds;
             
      printf("server waiting\n");
      //监听到客户端消息
      iResult = select(FD_SETSIZE,&testfds,(fd_set *)0,(fd_set *)0,(struct timeval *) 0);
             
      if(iResult < 1)
      {
    printf("server error\n");
    exit(-1);
      }  
             
      for(fd = 0; fd < FD_SETSIZE; fd++)
      {
     if(FD_ISSET(fd,&testfds))
     {
        if(fd == server_socket)
        {
          clinet_len = sizeof(client_address);
          client_socket = accept(server_socket,(struct sockaddr *)&client_address,( socklen_t *)&clinet_len);
          FD_SET(client_socket,&readfds);
          printf("addding client on fd %d\n",client_socket);
        } 
        else
        {
          ioctl(fd,FIONREAD,&nread);
                 
          if(nread == 0)
          {
        close(fd);
        FD_CLR(fd,&readfds);
        printf("remoing client on fd %d\n",fd);
          }
          else
          {
        read(fd,&ch,1);
        sleep(5);
        printf("sering client on fd %d\n",fd);
        ch++;
        write(fd,&ch,1);
          }
        } 
     } 
      }
             
             
  }
         
  return 0;
}      

客户端程序

#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  int sockfd;
  int len;
  struct sockaddr_in address;
  int result;
  char ch = 'A';
  sockfd = socket(AF_INET,SOCK_STREAM,0);
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = inet_addr("127.0.0.1");
  address.sin_port = htons(9734);
    
  len = sizeof(address);
  //将客户端的SOCKET与服务器端口进行链接
  result = connect(sockfd,(struct sockaddr *)&address,len);
  if(result == -1)
  {
    printf("connect error\n");
    exit(-1);
  } 
    
  write(sockfd,&ch,1);
  read(sockfd,&ch, 1);
  printf("char from server = %c \n",ch);
  close(sockfd);
  exit(0);
}