步骤
发端: 收端:
socket (创建套接字) socket(创建套接字)
bind (本机地址绑定)
listen (监听)
connect(请求连接) accept (处理连接)
send (发送数据) recv (发送数据)
recv (接收数据) send (接收数据)
close (关闭套接字) close (关闭套接字)
函数接口
(1)socket
TCP: socket(AF_INET, SOCK_STREAM, 0);
功能:
创建套接字
(2) listen
listen
int listen(int sockfd, int backlog);
功能:
监听发送三次握手连接的套接字,并放入等到处理队列中
参数:
sockfd:套接字文件描述符
backlog:等待队列的大小(最多存放尚未被处理的三次握手请求的个数),可以设置为0,即收到一个连接请求,处理一个连接请求
返回值:
成功返回0
失败返回-1
(3) accept
accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
处理等待队列中的第一个套接字
参数:
sockfd:套接字文件描述符
addr:存放发送方IP地址的空间首地址
addrlen:存放发送方IP地址的空间大小
返回值:
成功返回一个新的文件描述符
失败返回-1
(4) connect
connect
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
向接收方发起连接请求
参数:
sockfd:套接字文件描述符
addr:接收方的IP地址和端口号
addrlen:接收方的IP地址和端口号的大小
返回值:
成功返回0
失败返回-1
(5) send
send
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
向接收方发送数据
参数:
sockfd:套接字文件描述符
buf:要发送的数据的首地址
len:要发送的数据的长度
flags:标志位
返回值:
成功返回发送字节数
失败返回-1
(6) recv
recv
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收发送方发送的数据
参数:
sockfd:套接字文件描述符
buf:接收数据的缓冲区首地址
len:接收数据的缓冲区的大小
flags:标志位
返回值:
成功返回实际接收字节数
失败返回-1
对方关闭返回0
练习一:利用TCP实现简单收发功能
本机作为客户端
#include "../head.h"
int main()
{
int sockfd;
struct sockaddr_in recvaddr;
int ret=0;
char tmpbuff[256]={0};
ssize_t nsize=0;
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(30000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
//发送连接请求
ret=connect(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr) );
if(ret==-1)
{
return -1;
}
//发送数据
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1]='\0';
nsize=send(sockfd,tmpbuff,strlen(tmpbuff),0);
if(nsize==-1)
{
return -1;
}
printf("发送成功\n");
//接收数据
memset(tmpbuff,0,sizeof(tmpbuff));
nsize=recv(sockfd,tmpbuff,sizeof(tmpbuff),0);
if(nsize==-1)
{
return -1;
}
printf("接收到的字节数:%ld,内容为:%s\n",nsize,tmpbuff);
//关闭套接字
close(sockfd);
return 0;
}
本机作为服务端
#include "../head.h"
int main()
{
int sockfd;
struct sockaddr_in recvaddr;
ssize_t nsize;
int confd;
char tmpbuff[256]={0};
int ret=0;
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
perror("failed to sockfd");
return -1;
}
//绑定IP地址 端口号
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(30000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
ret=bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(ret==-1)
{
perror("failed to bind");
return -1;
}
//监听
ret=listen(sockfd,10);// 监听发送三次握手连接的套接字,并放入等到处理队列中,监听队列写0也可以,即发一个请求,处理一个请求
if(ret == -1)
{
perror("failed to listen");
return -1;
}
//处理连接请求
confd=accept(sockfd,NULL,NULL);//处理等待队列中的第一个套接字
if(confd==-1)
{
perror("failed to config");
return -1;
}
//接收数据
nsize=recv(confd,tmpbuff,sizeof(tmpbuff),0);
if(nsize==-1)
{
perror("failed to recv");
return -1;
}
printf("接收字节数:%ld,内容为:%s\n",nsize,tmpbuff);
//发送数据
memset(tmpbuff,0,sizeof(tmpbuff));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1]='\0';
nsize=send(confd,tmpbuff,strlen(tmpbuff),0);
if(nsize==-1)
{
perror("failed to send");
return -1;
}
printf("发送成功\n");
//关闭套接字
close(confd);
close(sockfd);
return 0;
}
练习二:利用TCP实现发送文件功能
发送文件端
#include "../head.h"
int main()
{
int sockfd;
FILE *fp=NULL;
char tmpbuff[1000]={0};
ssize_t nsize=0;
size_t size=0;
int ret=0;
struct sockaddr_in recvaddr;
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
perror("failed to socket");
return -1;
}
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(50000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
//建立连接
ret=connect(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(ret==-1)
{
perror("failed to connect");
return -1;
}
printf("连接成功\n");
//发送文件名
printf("请输入要发送的文件名:");
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1]='\0';
nsize=send(sockfd,tmpbuff,strlen(tmpbuff),0);
if(nsize==-1)
{
perror("failed to send");
return -1;
}
//打开文件
fp=fopen(tmpbuff,"r");
if(fp==NULL)
{
perror("failed to fopen");
return -1;
}
//发送数据
while(1)
{
size=fread(tmpbuff,1,sizeof(tmpbuff),fp);
if(size<=0)
{
break;
}
if(!strcmp(tmpbuff,".quit"))
{
break;
}
nsize=send(sockfd,tmpbuff,size,0);
if(nsize==-1)
{
perror("failed to send");
break;
}
}
//关闭套接字
close(sockfd);
//关闭文件
fclose(fp);
return 0;
}
接收文件端
#include "../head.h"
int main()
{
int sockfd;
char tmpbuff[1000]={0};
struct sockaddr_in recvaddr;
size_t size;
ssize_t nsize=0;
FILE *fp=NULL;
int ret=0;
int confd=0;
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
perror("failed to sockfd");
return -1;
}
//绑定
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(50000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
ret=bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(ret==-1)
{
perror("failed to bind");
return -1;
}
//监听
ret=listen(sockfd,10);
if(ret==-1)
{
perror("failed to listen");
return -1;
}
//处理连接
confd=accept(sockfd,NULL,NULL);
if(confd==-1)
{
perror("failed to accept");
return -1;
}
printf("连接成功\n");
//接收文件名
nsize=recv(confd,tmpbuff,sizeof(tmpbuff),0);
if(nsize==-1)
{
perror("failed to recv");
return -1;
}
printf("tmpbuff=%s\n",tmpbuff);
//创建文件
fp=fopen(tmpbuff,"w");
if(fp==NULL)
{
perror("failed to fopen");
return -1;
}
//接收文件内容
while(1)
{
nsize=recv(confd,tmpbuff,sizeof(tmpbuff),0);
if(nsize<=0)
{
break;
}
if(!strcmp(tmpbuff,".quit"))
{
break;
}
fwrite(tmpbuff,1,nsize,fp);
}
//关闭套接字
close(sockfd);
close(confd);
//关闭文件
fclose(fp);
return 0;
}
练习三:TCP 实现聊天功能(通过进程实现)
send.c
#include "../head.h"
int main()
{
int sockfd;
struct sockaddr_in recvaddr;
char tmpbuff[256]={0};
size_t nsize=0;
int ret=0;
pid_t pid;
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
perror("failed to socket");
return -1;
}
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(40000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
//建立连接
ret=connect(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(ret==-1)
{
perror("failed to connect");
return -1;
}
//创建进程
pid=fork();
if(pid==-1)
{
perror("failed to fork");
return -1;
}
//子进程负责发
if(pid==0)
{
while(1)
{
memset(tmpbuff,0,sizeof(tmpbuff));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1]='\0';
if(!strcmp(tmpbuff,".quit"))
{
break;
}
nsize=send(sockfd,tmpbuff,strlen(tmpbuff),0);
if(nsize<=0)
{
break;
}
}
kill(getppid(),SIGKILL);
}
//父进程负责收
else if(pid>0)
{
while(1)
{
memset(tmpbuff,0,sizeof(tmpbuff));
nsize=recv(sockfd,tmpbuff,sizeof(tmpbuff),0);
if(nsize<=0)
{
break;
}
if(!strcmp(tmpbuff,".quit"))
{
break;
}
printf("接收内容:%s\n",tmpbuff);
}
kill(pid,SIGKILL);
}
//关闭套接字
close(sockfd);
return 0;
}
recv.c
#include "../head.h"
int main()
{
int sockfd;
struct sockaddr_in recvaddr;
char tmpbuff[256]={0};
int confd;
size_t nsize=0;
int ret=0;
pid_t pid;
//创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
perror("failed to socket");
return -1;
}
//绑定
recvaddr.sin_family=AF_INET;
recvaddr.sin_port=htons(40000);
recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
ret=bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
if(ret==-1)
{
perror("failed to bind");
return -1;
}
//监听
ret=listen(sockfd,10);
if(ret==-1)
{
perror("failed to bind");
return -1;
}
//处理连接
confd=accept(sockfd,NULL,NULL);
if(confd==-1)
{
perror("failed to accept");
return -1;
}
//创建进程
pid=fork();
if(pid==-1)
{
perror("failed to fork");
return -1;
}
//子进程负责发
if(pid==0)
{
while(1)
{
memset(tmpbuff,0,sizeof(tmpbuff));
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1]='\0';
if(!strcmp(tmpbuff,".quit"))
{
break;
}
nsize=send(confd,tmpbuff,strlen(tmpbuff),0);
if(nsize<=0)
{
break;
}
}
kill(getppid(),SIGKILL);
}
//父进程负责收
else if(pid>0)
{
while(1)
{
memset(tmpbuff,0,sizeof(tmpbuff));
nsize=recv(confd,tmpbuff,sizeof(tmpbuff),0);
if(nsize<=0)
{
break;
}
if(!strcmp(tmpbuff,".quit"))
{
break;
}
printf("接收内容:%s\n",tmpbuff);
}
kill(pid,SIGKILL);
}
//关闭套接字
close(confd);
close(sockfd);
return 0;
}