TCP协议的位于数据传输层,其上一层是应用层,因此其目的是为了实现一个应用于另一个应用之间数据传输。
TCP协议需要进行三次握手实现数据发送和接收的同步。
第一次握手:客户端向服务端提出连接请求。这时TCP SYN标 志置位。客户端告诉服务端序列号区域合法,需要检查。客户端 在TCP报头的序列号区中插入自己的ISN。服务端收到该TCP分 段后,。
第二次握手:接收主机通过发回具有以下项目的数据段表示回 复:同步标志置位、即将发送的数据段的起始字节的顺序号、应 答并带有将收到的下一个数据段的字节顺序号
第三次握手:客户端确认收到服务端的ISN(ACK标志置位)。到此为止建立完整的TCP连接,开始全双工模式的数据传输过程。
1.客户端程序
#include
#include /* See NOTES */
#include
#include
#include /* superset of previous */
#include
#include
#include
#include
#define BUF_SIZE 512
/**********************所用到的函数*******************************
int socket(int domain, int type, int protocol);
创建套接字函数
AF_INET IPV4协议 SOCK_STREAM 流套接字
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
结构体sockaddr的成员
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET
in_port_t sin_port; /* port in network byte order
struct in_addr sin_addr; /* internet address
};
struct in_addr {
uint32_t s_addr; /* address in network byte order
};
int listen(int sockfd, int backlog);
sighandler_t signal(int signum, sighandler_t handler);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
char *fgets(char *s, int size, FILE *stream);//接收终端输入文件流
********************************************************/
int main()
{
int client_id;
struct sockaddr_in clientadd;
char buffer[BUF_SIZE];
client_id=socket(AF_INET,SOCK_STREAM,0); //创建套接字
clientadd.sin_family=AF_INET; //结构体成员赋值
clientadd.sin_port=htons(9736);//指定端口号
clientadd.sin_addr.s_addr=inet_addr("192.168.1.121"); //绑定IP地址,此处的IP为服务器IP
if(connect(client_id,(struct sockaddr *)&clientadd,sizeof(clientadd))==-1)//创建连接
{
//链接失败
printf("connect failed!\n");
exit(EXIT_FAILURE);
}
printf("please input:");
fgets(buffer,BUF_SIZE,stdin);
//向服务器写
write(client_id,buffer,BUF_SIZE);//将获取的数据发送至缓冲区
sleep(rand()%3);
memset(buffer,0,strlen(buffer));
read(client_id,buffer,BUF_SIZE);//接收返回数据
printf("You input:%s\n",buffer);
close(client_id);
return 0;
}
2.服务器程序
服务器程序主要实现从客户端接收数据,将接收到的数据返回给客户端。
#include
#include /* See NOTES */
#include
#include
#include /* superset of previous */
#include
#include
#include
#include
#define BUF_SIZE 512
/********用到的函数************************
int socket(int domain, int type, int protocol); 创建套接字
AF_INET IPV4协议 SOCK_STREAM
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET
in_port_t sin_port; /* port in network byte order
struct in_addr sin_addr; /* internet address
};
struct in_addr {
uint32_t s_addr; /* address in network byte order
};
int listen(int sockfd, int backlog);
sighandler_t signal(int signum, sighandler_t handler);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
********************************************************/
int main()
{
int socket_id,client_id;
struct sockaddr_in serveradd;
struct sockaddr_in clientadd;
int clientlen;
char buffer[BUF_SIZE+1];
socket_id=socket(AF_INET,SOCK_STREAM,0); //创建套接字
serveradd.sin_family=AF_INET;
serveradd.sin_port=htons(9736);//指定端口好
serveradd.sin_addr.s_addr=htonl(INADDR_ANY); //绑定IP地址 这里指定监听的IP地址是任何一个访问的IP
if(bind(socket_id,(struct sockaddr *)&serveradd,sizeof(serveradd))==-1)
{
//绑定失败
printf("connect failed!\n");
exit(EXIT_FAILURE);
}
//服务器端需要绑定端口和IP,服务器端需要对固定的端口和指定的IP进行监听,因此需要进行bind操作,而客户端部分不需要
listen(socket_id,5);//最大允许5个客户端访问
signal(SIGCHLD,SIG_IGN);
while(1)
{
clientlen=sizeof(clientadd);
printf("please waiting....\n");
client_id=accept(socket_id,(struct sockaddr *)&clientadd,&clientlen);//监听zijincheng
if(fork()==0)//新建一个子进程,在子进程中实现接收客户端发送过来的内容并将其发送回去,同时显示在终端上。
{
read(client_id,buffer,BUF_SIZE);
buffer[BUF_SIZE]='\0';
printf("You input :%s\n",buffer);
sleep(rand()%3);
write(client_id,buffer,BUF_SIZE);
close(client_id);
exit(EXIT_SUCCESS);
}
else
{
close(client_id);//关闭子进程
}
}
}