网络编程---TCP
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.自定义协议