天天看點

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);
}