歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux下Socket編程(2)

Linux下Socket編程(2)

日期:2017/2/25 10:38:58   编辑:Linux教程
 七、數據傳輸

  send()和recv()這兩個函數用於面向連接的socket上進行數據傳輸。

  send()函數原型為:

  include

  include

  size_t send(int sock_fd, const void *msg, int len, int flags);

  功能說明:發送數據。成功返回實際反送的數據的字節數。失敗返回-1,並置errno.

  參數說明: sock_fd是你想用來傳輸數據的socket描述符;msg是一個指向要發送數據的指針;len是以字節為單位的數據的長度;flags一般情況下置為0(關於該參數的用法可參照man手冊)。

  send()函數返回實際上發送出的字節數,可能會少於你希望發送的數據。在程序中應該將send()的返回值與欲發送的字節數進行比較。當send()返回值與len不匹配時,應該對這種情況進行處理。

  char *msg = "Hello!";

  int len, bytes_sent;

  ……

  len = strlen(msg);

  bytes_sent = send(sockfd, msg,len,0);

  ……

  recv()函數原型為:

  include

  include

  int recv(int sock_fd,void *buf,int len,unsigned int flags);

  功能說明:接受數據,成功返回0,否則,返回-1,並設置errno。

  參數說明:sock_fd是接受數據的socket描述符;buf 是存放接收數據的緩沖區;len是緩沖的長度。flags也被置為0。recv()返回實際上接收的字節數.

  sendto()和recvfrom()用於在無連接的數據報socket方式下進行數據傳輸。由於本地socket並沒有與遠端機器建立連接,所以在發送數據時應指明目的地址。

  sendto()函數原型為:

  int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);

  該函數比send()函數多了兩個參數,to表示目地機的IP地址和端口號信息,而tolen常常被賦值為sizeof (struct sockaddr)。sendto 函數也返回實際發送的數據字節長度或在出現發送錯誤時返回-1。

  recvfrom()函數原型為:

  int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

  from是一個struct sockaddr類型的變量,該變量保存源機的IP地址及端口號。fromlen常置為sizeof (struct sockaddr)。當recvfrom()返回時,fromlen包含實際存入from中的數據字節數。Recvfrom()函數返回接收到的字節數或當出現錯誤時返回-1,並置相應的errno。

  如果你對數據報socket調用了connect()函數時,你也可以利用send()和recv()進行數據傳輸,但該socket仍然是數據報socket,並且利用傳輸層的UDP服務。但在發送或接收數據報時,內核會自動為之加上目地和源地址信息。

  八、結束傳輸

  當所有的數據操作結束以後,你可以調用close()函數來釋放該socket,從而停止在該socket上的任何數據操作:

  int close(sock_fd);

  你也可以調用shutdown()函數來關閉該socket。該函數允許你只停止在某個方向上的數據傳輸,而一個方向上的數據傳輸繼續進行。如你可以關閉某socket的寫操作而允許繼續在該socket上接受數據,直至讀入所有數據。

  int shutdown(int sock_fd,int how);

  sockfd是需要關閉的socket的描述符。參數 how允許為shutdown操作選擇以下幾種方式:

  ·0-------不允許繼續接收數據

  ·1-------不允許繼續發送數據

  ·2-------不允許繼續發送和接收數據,

  ·均為允許則調用close ()

  shutdown在操作成功時返回0,在出現錯誤時返回-1並置相應errno。

  socket編程實例

  代碼實例中的服務器通過socket連接向客戶端發送字符串"Hello, you are connected!"。只要在服務器上運行該服務器軟件,在客戶端運行客戶軟件,客戶端就會收到該字符串。

  該服務器軟件代碼如下:

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #define SERVPORT 3333 /*服務器監聽端口號 */

  #define BACKLOG 10 /* 最大同時連接請求數 */

  int main()

  {

  int sock_fd,client_fd; /*sock_fd:監聽socket;client_fd:數據傳輸socket */

  struct sockaddr_in my_addr; /* 本機地址信息 */

  struct sockaddr_in remote_addr; /* 客戶端地址信息 */

  if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

  perror("socket創建出錯!");

  exit(1);

  }

  my_addr.sin_family=AF_INET;

  my_addr.sin_port=htons(SERVPORT);

  my_addr.sin_addr.s_addr = INADDR_ANY;

  bzero(&(my_addr.sin_zero),8);

  if (bind(sock_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {

  perror("bind出錯!");

  exit(1);

  }

  if (listen(sock_fd, BACKLOG) == -1) {

  perror("listen出錯!");

  exit(1);

  }

  while(1) {

  sin_size = sizeof(struct sockaddr_in);

  if ((client_fd = accept(sock_fd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) {

  perror("accept出錯");

  continue;

  }

  printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

  if (!fork()) { /* 子進程代碼段 */

  if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1)

  perror("send出錯!");

  close(client_fd);

  exit(0);

  }

  close(client_fd);

  }

  }

  return 0;

  }

Copyright © Linux教程網 All Rights Reserved