我们来了解一下TCP交互流程:
大致流程如下:
(1)服务器根据地址的类型(属于ipv4还是ipv6等)、socket类型(比如TCP、UDP)去创建socket,创建出的套接字socket本质上是个文件描述符。
(2)服务器绑定IP地址和端口号到套接字socket
(3)服务器socket**监听**端口号请求,随时准备接收客户端发来的连接,但这个时候服务器的socket并没有被打开。
(4)根据地址的类型(属于ipv4还是ipv6等)、socket类型(比如TCP、UDP)去**创建socke**t,创建出的套接字socket本质上也是个文件描述符。
(5)客户端根据服务器的ip地址和端口号,试图连接服务器
(6)服务器socket**接收到客户端的socket请求,被动打开,开始接收客户端的请求,并等待客户端返回连接信息。这个阶段,服务器的**accept方法是阻塞的,即等到刚才试图连接的客户端返回连接信息,accept方法才能返回,才能继续接收下一个最新的客户端连接请求。
(7)客户端连接成功,向服务器发送连接状态信息。
(8)服务器accept方法返回,连接成功
(9)客户端发送消息
(10)服务端接收消息
(11)客户端关闭
(12)服务端关闭
我们根据这个流程实现TCP交互:
tcpserver.c(服务器)
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//服务器
int main(int argc, char* argv[])
{
if(argc!=3){
printf("Usage %s is port\n",argv[0]);
return 1;
}
//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0){
perror("socket");
return 2;
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(argv[2]));
local.sin_addr.s_addr = inet_addr(argv[1]);
//绑定
if(bind(sock, (struct sockaddr*)&local, sizeof(local))<0)
{
perror("bind");
return 3;
}
//监听
if(listen(sock, 5)<0)
{
perror("listen");
return 4;
}
while(1)
{
char buf[1024];
buf[0]='\0';
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
//接受请求
int new_sock=accept(sock, (struct sockaddr*)&peer,&len);
if(new_sock<0)
{
perror("accept");
return 5;
}
inet_ntop(AF_INET, &peer.sin_addr, buf, sizeof(buf));
printf("get a connect,ip:%s,port:%d\n",buf, ntohs(peer.sin_port));
while(1)
{
ssize_t s = read(new_sock, buf, sizeof(buf));
if(s > 0)
{
buf[s]='\0';
printf("[%s:%d] %s",inet_ntoa(peer.sin_addr),\
ntohs(peer.sin_port),buf);
}
else
{
printf("client quit\n");
break;
}
write(new_sock,buf,strlen(buf)+1);
}
}
close(sock);
return 0;
}
tcpclient.c(客户端)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
if(argc != 3){
printf("Usage %s ip port\n",argv[0]);
return 1;
}
//创建套接字
int sock=socket(AF_INET,SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
return 2;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
//建立连接
int ret = connect(sock, (struct sockaddr*)&server, \
sizeof(server));
if(ret < 0){
perror("connect");
return 3;
}
printf("connect success...\n");
while(1){
char buf[1024];//缓冲区
buf[0]='\0';
printf("Please Enter:");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf));
}
write(sock, buf, sizeof(buf));
if(strncmp(buf, "quit",4)==0)
break;
read(sock, buf, sizeof(buf));
printf("server :%s",buf);
}
close(sock);
return 0;
}
在本地网络中建立连接,运行结果如下: