1.TCP:傳輸控制協議,位于傳輸層
2.TCP的特性:
a.使用流式套接字,數據連續,有順序
b.TCP是可靠傳輸,有有應答機制ACK,即收到數據后會明確告知發送方已收到數據;若發送方沒有在預計時間收到應答,則會自動重傳剛剛的數據
c.TCP在建立連接后傳輸鏈路會一直存在
d.TCP為全雙工通信,在同一時刻既可以收也可以發
e.為滿足同時收發,TCP存在雙緩沖區,每個大小為64k,當緩沖區滿時,會發生相應阻塞
3.TCP的收發過程:
三次握手過程
1.客戶端向服務端發送SYN連接請求信號和隨機初始序列號 (Client ISN)
2.服務端向客戶端發送ACK確認信號和SYN連接請求信號,并發送自己的隨機初始序列號 (Server ISN)
3.客戶端向服務端發送ACK確認信號
四次揮手過程
a.客戶端向服務端發送FIN結束連接請求信號,和SYN連接請求信號
b.服務端向客戶端發送ACK確認信號
c.服務端向客戶端發送FIN結束連接請求信號和ACK確認信號
d.客戶端向服務端發送ACK確認信號,連接結束
4.TCP函數的調用順序
1)TCP服務端
a.socket()產生一個監聽套接字
b.bind()綁定源地址
c.listen()監聽
d.accept()建立連接,產生通信套接字,即三次握手過程
e.read(),write()
f.close()關閉監聽套接字
2)TCP客戶端
a.socket()產生一個套接字
b.accept()建立連接,產生通信套接字,即三次握手過程
c.read(),write()
d.close()關閉套接字
5.使用TCP從客戶端向服務端發送一個照片文件
ser端
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr *(SA);
int main(int argc, char **argv)
{int fd=open("2.jpg", O_WRONLY|O_CREAT|O_TRUNC,0666);int listfd=socket(AF_INET,SOCK_STREAM,0);if(-1==listfd){perror("socket fail\n");return 1;}struct sockaddr_in ser,cil;bzero(&ser, sizeof(ser));bzero(&cil, sizeof(cil));socklen_t len=sizeof(cil);ser.sin_family=AF_INET;ser.sin_port=htons(50000);//127.0.0.1表示自己的ip地址,本機自己收發//ser.sin_addr.s_addr=inet_addr("127.0.0.1");ser.sin_addr.s_addr=INADDR_ANY;int ret=bind(listfd, (SA)&ser, sizeof(ser));if(-1==ret){perror("blind");return 1;}listen(listfd, 3);//三次握手的排隊數int conn=accept(listfd, (SA)&cil, &len);//conn為通信套接字if(conn==-1){perror("accept");return 1;}while(1){char buf[1024]={0};//int ret=recv(conn, buf, sizeof(buf), 0);int ret=recvfrom(conn, buf, sizeof(buf), 0,(SA)&cil,&len);if(ret<=0)//==0說明對方連接斷開{break;}write(fd, buf, ret);bzero(buf, sizeof(buf));strcpy(buf,"ok");send(conn, buf, strlen(buf), 0);}close(listfd);close(conn);return 0;
}
cli端
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr *(SA);
int main(int argc, char **argv)
{int fd=open("1.jpg", O_RDONLY);if(-1==fd){perror("open");return 1;}int conn=socket(AF_INET, SOCK_STREAM, 0);if(-1==conn){perror("socket");return 1;}struct sockaddr_in ser;bzero(&ser,sizeof(ser));ser.sin_family=AF_INET;ser.sin_port=htons(50000);ser.sin_addr.s_addr=INADDR_ANY;int ret=connect(conn, (SA)&ser, sizeof(ser));if(-1==ret){perror("connect error\n");return 1;}while (1){char buf[1024]={0};int ret=read(fd, buf, sizeof(buf));if(ret<=0){break;}send(conn, buf, ret, 0);bzero(buf, sizeof(buf));recv(conn, buf, sizeof(buf), 0);}close(conn);close(fd);return 0;
}
6.數據的粘包
發送方發送數據,接收方無法解析數據
解決方案:
a.設置邊界
b.固定大小
c.自定義協議