1. 程式人生 > >基於Linux的C++之網路程式設計

基於Linux的C++之網路程式設計

套接字的基本概念

通訊型別: 控制套接字如何傳輸和處理資料,資料以包的形式傳輸

  • 連線(connection)型別:確保所有包依序傳輸,如果丟包,則請求重傳
  • 資料報(datagram)型別:不保證包的到達順序,包可能丟失

名空間: 指定套接字地址格式

  • 本地名空間:套接字地址為普通檔名
  • Internet名空間:套接字地址由Internet地址和埠號(用於區分一臺主機上的多個套接字)確定

協議: 確定資料如何傳輸

套接字函式

socket()函式: 建立套接字

  • 原型:int socket(int domain,int type,int protocol);
  • 引數:名空間、通訊型別和協議
  • 名空間:PF_LOCAL(本地)或PF_INET(Internet)
  • 通訊型別:SOCK_STREAM(連線型別)或SOCK_DGRAM(資料報型別)
  • 協議:傳遞0,讓系統自動選擇協議(通常為最佳協議)
  • 返回值:套接字描述符

close()函式: 釋放套接字

  • 原型:int close(int fd);

connect()函式: 建立兩個套接字之間的連線

  • 客戶發起此係統呼叫,試圖與伺服器建立套接字連線
  • 原型:int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
  • 引數:sockfd 為檔案描述符; addr 為指向套接字地址結構體指標(伺服器地址);addrlen 為伺服器地址字串的長度
  • 返回值:0 連線成功; -1 連線失敗

send()函式: 傳送資料

  • 原型: ssize_t send(int sockfd,const void* buf,size_t len,int flags);
  • 只有在套接字處於連線狀態時才可呼叫

bind()函式: 繫結套接字與其伺服器地址

  • 原型:int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);

listen()函式: 偵聽客戶連線

  • 原型:int listen(int sockfd,int backlog);
  • 引數:backlog 指定有多少個連線可以進入佇列,超出該值的連線將被拋棄

accept()函式: 接受連線,為該連線建立一個新的套接字

  • 原型 int accept(int sockfd,struct sockaddr* addr,socklen_t addrlen);
  • 引數: addr 為指向套接字地址結構體(客戶地址)的指標
  • 返回值:建立一個新的套接字,以接受客戶連線,返回值為新的套接字檔案描述符
  • 原先套接字檔案描述符可以繼續接受新連線

本地套接字示例:伺服器端

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

//持續讀取訊息,直到套接字關閉或接收到客戶傳送的“quit”訊息
// 前者返回true,後者返回 false,伺服器隨後將停止服務

bool Serve(int client_socket)
{
  while (true) {
    int length;
    char* msg;
    //從套接字中讀取文字訊息的長度,返回值為0表示客戶連線已關閉
    if(read(client_socket,&length,sizeof(length)) == 0)
      return true;
    msg = new char[length];
    read(client_socket,msg,length);
    std::cout<<msg<<std::endl;
    if(!strcmp(msg,"quit"))  {delete[] msg,msg = NULL;return false;}
    else delete[] msg, msg = NULL;
  }
}

int main(int argc,char* const argv[])
{
  const char* const socket_name = argv[1];
  ing socket_fd;
  struct sockaddr_un name;
  bool serving = true;
  //建立套接字
  socket_fd = socket(PF_LOCAL,SOCK_STREAM,0);
  //設定伺服器性質
  name.sun_family = AF_LOCAL;
  strcpy(name.sun_path,socket_name);
  // 繫結套接字
  bind(socket_fd,(struct sockaddr*)&name,SUN_LEN(&name));
  //偵聽客戶連線
  listen(socket_fd,5);
  //重複接受連線,直到某個客戶發出“quit”訊息
  while(serving)
  {
    struct sockaddr_un client_name;
    socklen_t client_name_len;
    int client_socket_fd;
    //接受客戶連線請求
    client_socket_fd = accept(socket_fd,(struct sockaddr*)&client_name,&client_name_len);
    serving = Serve(client_socket_fd); //服務連線請求
    close(socket_fd);//關閉客戶連線
  }
  close(socket_fd);
  unlink(socket_name); //刪除套接字檔案
  return 0;
}

本地套接字示例,客戶端

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

void SendMsg(int socket_fd,const char* msg)
{
  int length = strlen(msg) + 1;
  write(socket_fd,&length,sizeof(length));
  write(socket_fd,msg,length);
}
int main(int argc, char const *argv[]) {
  const char* const socket_name = argv[1];
  const char* const msg = argv[2];
  int socket_fd;
  struct sockaddr_un name;
  //建立套接字
  socket_fd = socket(PF_LOCAL,SOCK_STREAM,0);
  //套接字地址中儲存伺服器名稱
  name.sun_family = AF_LOCAL;
  strcpy(name.sun_path,socket_name);
  //連線
  connect(socket_fd,(struct sockaddr*)&name,SUN_LEN(&name));
  //傳送訊息
  SendMsg(socket_fd,msg);
  close(socket_fd);
  return 0;
}

本地套接字示例:執行

程式測試執行

  • 編譯連結服務端程式和客戶端程式
  • 進入服務端程式目錄,在終端輸入:./server/tmp/socket; ./server 為伺服器端程式名, /tmp/socket 為本伺服器啟動後的套接字檔名
  • 進入客戶端程式目錄,在終端中輸入:./client/tmp/socket"Hello World!"; ./client 為客戶端程式名
  • 停止伺服器,在客戶端輸入命令:./client/tmp/socket"quit"

網路套接字示例:客戶端

#include <iostream>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

// 請求Web伺服器的主頁
void GetHomepage(int socket_fd)
{
  char buffer[8192];
  sprintf(buffer,"GET /\n");
  write(socket_fd,buffer,strlen(buffer));
  while(true){
    ssize_t count = read(socket_fd,buffer,8192);
    if(count == 0) return;
    fwrite(buffer,sizeof(char),count,stdout);
  }
}

int main(int argc, char const *argv[])
{
  int socket_fd;
  struct sockaddr_in name;
  struct hostent* hostinfo;
  socket_fd = socket(PF_INET,SOCK_STREAM,0);
  name.sin_family = AF_INET;
  hostinfo =  gethostbname(argv[1]);
  if(hostinfo == NULL) return 1;
  else name.sin_addr = *((struct in_addr*)hostinfo ->h_addr);
  name.sin_port = htons(80);
  if(connect(socket_fd,(struct in_addr*)&name,sizeof(struct sockaddr_in)) == -1) {
  perror("Failure to connect the server.");
  return 2;
}
  GetHomepage(socket_fd);
  return 0;
}

“`