1. 程式人生 > >網絡通信中tcp多客戶端連接

網絡通信中tcp多客戶端連接

函數 sock 之間 not 函數返回 封裝 初始化 返回 在服務器

  網絡編程中的tcp實例太多了,自己也寫了好幾次(羞愧),今天在想一對一的TCP知道怎麽寫了,可是一對多的怎麽辦呢?服務器是如何知道要給那個發送數據呢?做開發的同學應該經常聽說uid這個屬性。可以為什麽通過UID就知道要發送的數據是給正確的用戶的呢?

  不怎麽忙的時候。仔細的了解了一下TCP的幾個API和其中的參數。下面來看一下這幾個API和參數:

  1. 描述:當創建socket套接字後,該套接字並沒有魚本機地址和端口等信息相連接,而bind函數將完成這些工作

包含的頭文件
<sys/types.h>
<sys/socket.h>
原型:
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
返回值:
    0:成功
    1:失敗

返回的錯誤碼

EACCES:地址受到保護,用戶非超級用戶。
EADDRINUSE:指定的地址已經在使用。
EBADF:sockfd參數為非法的文件描述符。
EINVAL:socket已經和地址綁定。
ENOTSOCK:參數sockfd為文件描述符

  1. 描述:listen函數使用主動連接套接口變為被連接套接口,是的一個進程能夠接受其他請求,使之成為一個服務器進程。總之TCP服務器中LISTEN函數將進程變為一個服務器進程,將主動變成了被動
包含頭文件
#include<sys/socket.h>
原型:
int listen(int sockfd, int backlog)
返回值:
    0:成功
    1:失敗

參數解析:

參數1:socket

  被listen函數作用的套接字,sockfd之前由socket函數返回。在被socket函數返回的套接字fd之時,它是一個主動連接的套接字,也就是此時系統假設用戶會對這個套接字調用connect函數,期待它主動與其它進程連接,然後在服務器編程中,用戶希望這個套接字可以接受外來的連接請求,也就是被動等待用戶來連接。由於系統默認時認為一個套接字是主動連接的,所以需要通過某種方式來告訴系統,用戶進程通過系統調用listen來完成這件事。

參數2:backlog:

  這個參數涉及到一些網絡的細節。在進程正理一個一個連接請求的時候,可能還存在其它的連接請求。因為TCP連接是一個過程,所以可能存在一種半連接的狀態,有時由於同時嘗試連接的用戶過多,使得服務器進程無法快速地完成連接請求。如果這個情況出現了,服務器進程希望內核如何處理呢?內核會在自己的進程空間裏維護一個隊列以跟蹤這些完成的連接但服務器進程還沒有接手處理或正在進行的連接,這樣的一個隊列內核不可能讓其任意大,所以必須有一個大小的上限。這個backlog告訴內核使用這個數值作為上限。毫無疑問,服務器進程不能隨便指定一個數值,內核有一個許可的範圍。這個範圍是實現相關的。很難有某種統一,一般這個值會小30以內。

  1. 描述:accept().接受客戶端的連接,並建立一個與客戶端對應的socket。

  需註意:在服務器端,socket()返回的套接字用於監聽(listen)和接受(accept)客戶端的連接請求。這個套接字不能用於與客戶端之間發送和接收數據。accept()接受一個客戶端的連接請求,並返回一個新的套接字。所謂“新的”就是說這個套接字與socket()返回的用於監聽和接受客戶端的連接請求的套接字不是同一個套接字。與本次接受的客戶端的通信是通過在這個新的套接字上發送和接收數據來完成的。

  

頭文件:
#include <sys/types.h>
#include <sys/socket.h>
原型:
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
返回值:
    >0:成功
    <0:失敗,並返回錯誤碼

參數解釋:

  socketfd:利用系統調用socket()建立的套接字描述符,通過bind()綁定到一個本地地址(一般為服務器的套接字),並且通過listen()一直在監聽連接;

  addr:指向struct sockaddr的指針,該結構用通訊層服務器對等套接字的地址(一般為客戶端地址)填寫,返回地址addr的確切格式由套接字的地址類別(比如TCP或UDP)決定;若addr為NULL,沒有有效地址填寫,這種情況下,addrlen也不使用,應該置為NULL;

  addrlen:一個值結果參數,調用函數必須初始化為包含addr所指向結構大小的數值,函數返回時包含對等地址(一般為服務器地址)的實際數值;

  • 來看一下服務器的大概流程:
1:    server_sock = socket();
2:    bind(server_sock);
3:    listen(server_sock);
4:    client_sock = accept(server_sock);
5:    close(server_sock);
6:    send(client_sock, data);
7:    recv(client_sock, data);
8:    close(client_sock);

是不是發現第四點新建立了一個套接字!而發送和接受數據的套接字都是accpet後新建的,沒錯服務器就是通過這個套接字向正確的客戶端發送數據的。你可能會說常見的都是通過UID發送的。沒錯!那是因為開發者做了一層封裝,將此套接字作為Value和用戶的uid作為key存到了一個名為hashmap的對應關系中,所以才會有你所了解的通過UID給用戶發送數據。

網絡通信中tcp多客戶端連接