關於socket應用:一個不斷監聽一個程序的伺服器以及傳送資訊的客戶端 TCP的三次握手和四次揮手
大端節序:高位節放在低地址
小端節序:高位節放在高地址
PC多采用小端節序,而手機多采用大端節序,在網路傳播過程中一律轉換成大端節序,所以大端節序也稱為網路位元組序。
主要標頭檔案#include <sys/socket.h>
linux提供了四個函式來完成主機位元組序和網路位元組序的轉換,我常用的是
#include <netinet/in.h>
unsigned short int htons(unsigned short int hostshort);
TCP/IP有sockaddr_in和sockaddr_in6兩個專用socket地質結構體,用於IPv4和IPv6,個人常用sockaddr_in
struct sockaddr_in
{
sa_family_t sin_family;//地址族
u_int16_t sin_port; //埠號
struct in_addr sin_addr; //IPv4地址結構體
} ;
struct in_addr
{
u_int32_t s_addr; //IPv4地址,要用網路位元組序表示
};
||||||||||特別注意的是所有的專用socket地址型別的變數在使用的時候都需要轉化為通用socket地址型別sockaddr,因為所有socket程式設計介面使用的地址引數的型別都是sockaddr.
IP地址轉換函式
對於IPv4,用的是點分十進位制字串表示,但是程式設計中我們需要先把它們轉化為整數(二進位制)方能使用.
#include <arpa/inet.h>
int_addr_t inet_addr(const char* strptr);//作用是把原先的點分十進位制字串轉換成網路位元組序表示的IPv4地址.
(1) 建立socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
domain引數告訴系統使用哪個底層協議族AF_INET(OR PF_INET)表示的是IPv4
type用於指定服務型別,SOCK_STREAM(流服務),SOCK_DGRAM(資料報)服務。取用SOCK_STREAM表示用的是TCP協議,用SOCK_DGRAM則表示用的是UDP服務。
protocol通常設定為0
返回值:成功則返回一個檔案描述符,失敗就返回-1
(2)命名socket
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen);
這個操作客戶端一般不用,他將一個socket與socket地址繫結在一起,這樣客戶端才知道如何連線他。
bind將my_addr所指的socket地址分配給未命名的sockfd檔案描述符
addrlen指出該socket地址的長度
bind成功返回0,失敗返回-1.
(3)監聽sockfd
sockfd被命名之後,我們還需要建立一個監聽佇列來存放待處理的客戶連線。
#include <sys/socket.h>
int listen(int sockfd,int backlog);
sockfd指定被監聽的sockfd,backlog提示核心監聽佇列的最大長度。只表示處於完全連線狀態的socket的上限
(4)接受連線
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr* addr,socklen_t *addrlen);
addr的作用是用來監聽遠端地址
sockfd的作用是執行過listen系統呼叫的監聽socket。
(5)發起連線
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr* serv_addr,socklen_t addrlen);
sockfd,是由系統呼叫產生的,第二個引數是監聽的sockfd地址,addrlen指定地址長度
成功0,失敗-1
(6)關閉連線
#include <unistd.h>
int close(int fd);
每使用一次fd引用計數減一,知道減到0為止。
(7)TCP資料讀寫
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
ssize_t send(int sockfd,const void* buf,size_t len,int flags);
向sockfd上讀寫資料,最後一個引數一般都是0
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5);
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
while(1)
{
if(c<0)
{
continue;
}
char buff[128] = {0};
recv(c,buff,127,0);
printf("%s",buff);
}
close(c);
return 0;
}
客戶端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;//雖然操作一樣,但是客戶端是為了去連結服務端
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);//轉換成大端
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
//要用就必須先執行起來
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//連結到服務端上面
assert(res!=-1);
//執行到這個地方說明三次握手完成
while(1)
{
printf("input:\n");
char buff[128] = {0};
fgets(buff,128,stdin);//fgets會用到空格回車
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);//把收到的訊息再發送出去
memset(buff,0,128);
}
close(sockfd);//關閉
return 0;
}
ACK : TCP協議規定,只有ACK=1時有效,也規定連線建立後所有傳送的報文的ACK必須為1
SYN(SYNchronization) : 在連線建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連線請求報文。對方若同意建立連線,則應在響應報文中使SYN=1和ACK=1. 因此, SYN置1就表示這是一個連線請求或連線接受報文。
FIN (finis)即完,終結的意思, 用來釋放一個連線。當 FIN = 1 時,表明此報文段的傳送方的資料已經發送完畢,並要求釋放連線。
TCP三次握手四次揮手中三種報文的作用首先由Client發出請求連線即 SYN=1 ACK=0 (請看頭欄位的介紹), TCP規定SYN=1時不能攜帶資料,但要消耗一個序號,因此宣告自己的序號是 seq=x
然後 Server 進行回覆確認,即 SYN=1 ACK=1 seq=y, ack=x+1,
(為什麼在連線的時候伺服器端在接收到了客戶端的SYN後返回的時候返回的是SYN=1 ACK=1...)的原因作為補充
http://blog.csdn.net/oney139/article/details/8103223
這位前輩寫的很詳細,我做個記錄方便以後複習