linux
一.基礎知識服務器
客戶端與服務器之間將展開一段結構化對話,叫協議。網絡
在C語言中,若是寫一個與網絡通訊的程序,就須要新的數據流-套接字,套接字是雙向的,既能夠輸入也能夠輸出數據結構
1.使用socket()函數建立一個套接字數據流socket
#include <sys/socket.h> int xxxx = socket(PF_INET, SOCK_STREAM, 0);
xxxx是套接字名字函數
套接字與客戶端程序通訊,服務器須要經歷,綁定端口,監聽,接受鏈接,開始通訊,四個階段spa
服務啓動時,服務器會爲每項服務分配一個端口,服務器啓動時,須要告訴操做系統將要使用哪一個端口,這個過程叫作端口綁定。操作系統
2.這些代碼將建立一個表示"互聯網xxx端口"的套接字名code
#include <arpa/inet.h> struct sockeaddr_in xxxx; xxxx.sin_family = PF_INET; xxxx.sin+port = (in_port_t)htons(端口號); xxxx.sin_addr.s_addr = htonl(INADDR_ANY); int x = bind (套接字名字, (struct sockaddr * ) &xxxx, sizeof(name));
3.設置客戶端鏈接服務器的排隊數量blog
listen(套接字名字, xx)
xx爲人數
在linux操做系統的/etc/services文件中能夠查看經常使用服務使用的端口號
4.保存鏈接客戶端的詳細信息
struct sockaddr_storage xxxx; unsigned int address_size = sizeof(client_addr); int connect_d = accept(listener_d, (struct sockaddr *) &client_addr, &address_size);
套接字的輸出方法:
二.使用send()函數寫數據
send(套接字名稱, xxxx, strlen(xxx), 0)
xxx和strlen(xxx)是消息和消息長度
0是高級參數填0便可
綁定端口有延時的解決辦法,當使用某個端口綁定了套接字後,在接下來的30秒內,操做系統不容許任何程序綁定它,包括上次綁定這個端口的程序,咱們在綁定前設置套接字的某個選項,就能夠解決這個問題了。
int reuse = 1; setsockopt(套接字名字, SQL_SOCKET, SO_REUSEADDR, (char * )&reuse, sizeof(int));
三.使用recv()函數讀數據
recv (接收的描述符,字符變量的緩衝區,<要讀取幾個字節>, 0);
1.字符串不以\0結尾
2.當用戶在客戶端輸入文本時用\r\n結尾
3.recv()將返回字符個數,若是發生錯誤就返回-1,若是客戶端關閉鏈接就返回0
4.recv調用不必定能一次接收全部字符,須要配合循環,讀取字符。
例如:
int read_in (int socket, char * buf, int len) { int c = recv(socket, buf, len, 0); }
四.爲每一個客服端複製一份子進程
服務器在運行一份套接字進程給第一個用戶時,沒法運行第二個進程給第二個用戶,所以使用fork()爲每一個用戶建立一個子進程。
服務器父進程只須要用主監聽套接字,所以關閉副套接字,子進程需處理副套接字,關閉主監聽套接字
五.建立ip地址套接字
1.客戶端套接字的建立:
int xxx = socket (PF_INET, SOCK_STREAM, 0);
2.客戶端和服務器處理套接字的方法不一樣,服務器會把套接字綁定到本地端口,而客戶端會把套接字鏈接至遠程端口。
struct sockaddr_in xxx; memset(&xxx, 0, sizeof(xxx)); xxx.sin_family = PF_INET; xxx.sin_addr.s_addr = inet_addr("ip地址"); xxx.sin_port = htons(端口號); connect(xxx, (struct sockaddr *) &xxx, sizeof(xxx)); 鏈接套接字至遠程端口
六.使用域名建立套接字
域名系統,計算機發送數據包時須要在地址一欄填寫數字形式的ip地址,而dns能夠把域名轉化爲ip地址
建立域名套接字:
#include<netdb.h> struct addrinfo * xxx; struct addrinfo xxxx; memset(&xxxx, 0, sizeof(xxxx)); xxxx.ai_family = PF_UNSPEC; xxxx.ai_socktype = SOCK_STREAM; getaddrinfo("域名", "端口", &xxxx, &xxx); getaddrinfo會在堆上建立一個xxx名字的新數據結構給定域名和端口號。
隨後建立套接字
int x = socket(xxx->ai_family, xxx->ai_socktype, xxx->ai_protocal); connect(x, xxx->ai_addr, xxx->ai_addrlen); freeaddrinfo(xxx);鏈接之後刪除地址數據