TCP编程流程图
TCP服务端编程步骤
(1) 建立套接字stock()
服务端:
int listen_fd;
listen_fd=socket(AF_INET,SOCK_STREAM,0);
if(listen_fd<0)
{
perror("Failed to create socket:");
return -1;
}
客服端:
int client_fd;
client_fd=socket(AF_INET,SOCK_STREAM,0); //网络端应用程序
(2) 对创建的套接字指定ip地址和端口号(bind)
① 服务端:提供服务的一端,它始终等待别人的服务请求,只有“别人主动找它联系,而永远不会主动找别人联系”。为了让别人能够找到它,它必须公开其socket属性:ip地址——端口号
因此需要通过bind()函数显式指定其ip地址和端口号
② 客户端:请求服务的一端,主动联系别人的一方,因为它并不需别人来找它,所以无须公开其socket属性
因此不需要通过bind()函数显式指定其ip地址和端口号,该soket的其ip地址和端口在通信时由系统自动分配
服务端:
int ret;
int sock_size=sizeof(struct sockaddr_in);
struct sockaddr_in server_addr;
bzero(&server_addr,sock_size);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=INADDR_ANY;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
ret=bind(listen_fd,(struct sockaddr*)&server_addr,sock_size);
if(ret==0)
{
printf("Bind Successfully!\n");
}
注意:INADDR_ANY表示可以接受本机所有网卡所有ip地址的数据;如果把INADDR_ANY换成inet_addr(“192.168.0.103”),则表示只会接收本机ip地址为192.168.0.103上的数据
(3) 对套接字进行侦听(listen)
通常会建立一个连接队列,进行通信的只能一个客户端
让sockfd处处于监听外来请求的状态,可以把请求加入到请求队列里面等候处理(accept()函数)!
服务端:
ret=listen(listen_fd,MAXCONN);
if(ret==0)
{
printf("Listen Successfully!\n");
}
(4) 套接字等待连接(accept)
它的调用将意味着服务端开始处理外来请求,如果没有外来请求(也就是没有listen到请求进来)默认情况下则阻塞
服务端:
int comm_fd;
while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
{
信息交互
}
TCP客服端编程步骤
(1) 向服务端发起连接请求connect()
【前提是服务端已经进入等待连接accept】 客户端套接字sockfd向服务器端serv_addr发起连接请求
客户端:
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
ret=connect(client_fd,(struct sockaddr*)&server_addr,sock_size);
if(ret<0)
{
perror("Failed to connect:");
return -1;
}
printf("Connect successfully!\n");
while(1)
{
信息交互
}
连接请求成功后通过send()和recv()通信
(1) 发送信息send()
当send返回时,并不是表示数据已经发送到了对方,而仅仅表示数据已经到了协议栈的缓冲区中。
(2) 接收信息recv()
默认情况下,当没有可接收的数据时则阻塞,参数len表示最多接收多少个字节数, 成功的接受的字节数完全可以小于len!!
客服端:
int ret;
int count;
struct sockaddr_in server_addr;
char buf[512];
char recv_buf[512];
while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
{
char ipaddr[16];
inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ipaddr,16);
printf("A connection come on:%s\n",ipaddr);
while(1)
{
char buff[512];
int count;
count=read(comm_fd,buff,511);
if(count>0)
{
buff[count]=0;
printf("A String from %s:%s\n",ipaddr,buff);
if(strncmp(buff,"quit",4)==0)
{
printf("A talking is over!\n");
break;
}
write(comm_fd,buff,count);
}
else
{
printf("A talking is over!\n");
break;
}
}
}
服务端:
while(1)
{
char buff[512];
int count;
count=read(comm_fd,buff,511);
if(count>0)
{
buff[count]=0;
printf("A String from %s:%s\n",ipaddr,buff);
if(strncmp(buff,"quit",4)==0)
{
printf("A talking is over!\n");
break;
}
write(comm_fd,buff,count);
}
else
{
printf("A talking is over!\n");
break;
}
}
}
实验要求:
服务端:
接收客户端所传输的文本信息同时显示客户端的IP地址并把文本信息回传给客户端,当收到quit时退出本次服务
客户端:
把从键盘输入的字符串发送给客户端,同时等待服务端的回传信息
客服端代码:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h> //socket函数所需的头函数
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
int main(int argc,char **argv)
{
int client_fd;
int ret;
int count;
struct sockaddr_in server_addr;
char buf[512];
char recv_buf[512];
int sock_size=sizeof(struct sockaddr_in);
if(argc<2)
{
printf("Usage:./client serverip\n");
return 0;
}
bzero(&server_addr,sock_size);
client_fd=socket(AF_INET,SOCK_STREAM,0); //网络端应用程序
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
ret=connect(client_fd,(struct sockaddr*)&server_addr,sock_size);
if(ret<0)
{
perror("Failed to connect:");
return -1;
}
printf("Connect successfully!\n");
while(1)
{
fgets(buf,512,stdin);
ret=write(client_fd,buf,strlen(buf));
if(ret<=0)
break;
if(strncmp(buf,"quit",4)==0)
break;
count=read(client_fd,recv_buf,511);
if(count>0)
{
recv_buf[count]=0;
printf("Echo:%s\n",recv_buf);
}
else
{
break;
}
}
close(client_fd);
return 0;
}
服务端代码:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#define MAXCONN 8
int main()
{
int listen_fd,comm_fd;
int ret;
int i=1;
struct sockaddr_in server_addr,client_addr;
int sock_size=sizeof(struct sockaddr_in);
listen_fd=socket(AF_INET,SOCK_STREAM,0);
if(listen_fd<0)
{
perror("Failed to create socket:");
return -1;
}
bzero(&server_addr,sock_size);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=INADDR_ANY;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
ret=bind(listen_fd,(struct sockaddr*)&server_addr,sock_size);
if(ret==0)
{
printf("Bind Successfully!\n");
}
ret=listen(listen_fd,MAXCONN);
if(ret==0)
{
printf("Listen Successfully!\n");
}
while((comm_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&sock_size))>=0)
{
char ipaddr[16];
inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ipaddr,16);
printf("A connection come on:%s\n",ipaddr);
while(1)
{
char buff[512];
int count;
count=read(comm_fd,buff,511);
if(count>0)
{
buff[count]=0;
printf("A String from %s:%s\n",ipaddr,buff);
if(strncmp(buff,"quit",4)==0)
{
printf("A talking is over!\n");
break;
}
write(comm_fd,buff,count);
}
else
{
printf("A talking is over!\n");
break;
}
}
}
close(listen_fd);
return 0;
}
编程步骤:
(1) 将服务端代码和客服端代码在Linux下执行
gcc -o sever sever.c
gcc -o client client.c
(2) 打开网络调试助手,设置成tcp客服端,端口号0
(3) 打开两个终端窗口
(这两步不能先后调换)
先执行服务端;后执行客服端,连接本机ip