套接字通信基本流程图:
服务端首先需要使用socket()创建套接字的文件描述符,然后bind()为套接字绑定IP地址和端口号,供客户端进行连接;
有了IP和端口号后,便开始使用listen()监听数据。
其中的固定格式为sockaddr,但为了方便一般使用sockaddr_in。
accept()用来准备和客户端连接,该函数是阻塞函数,当没有客户端连接时,会一直阻塞;且一次只能连接一个客户端。
recv()和send()成对使用,分别用来响应和发送数据。
close()用来关闭文件描述符,即关闭连接。
客户端同样需要创建一个套接字的文件描述符,但不需要绑定IP和端口号,connect()会自动寻找一个未被使用的端口号给客户端通信。
服务端:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
int main()
{
//创建监听套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd == -1)
{
perror("socket");
return -1;
}
//绑定ip 端口号
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议簇
saddr.sin_port = htons(9999); //端口号 主机转网络字节序
saddr.sin_addr.s_addr = INADDR_ANY; //自动识别IP
int ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret == -1)
{
perror("bind");
return -1;
}
//开始监听
ret = listen(fd,128);
if(ret == -1)
{
perror("listen");
return -1;
}
//准备接受客户端连接
struct sockaddr_in caddr;
int addrlen = sizeof(caddr);
int cfd = accept(fd,(struct sockaddr*)&caddr,&addrlen);
if(cfd == -1)
{
perror("accept");
return -1;
}
//连接成功,打印客户端ip 和 端口号
char ip[32];
printf("IP地址:%s,端口:%d\n",
inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),
ntohs(caddr.sin_port));
//通信
while(1)
{
//接收数据
char buff[1024];
int len = recv(cfd,buff,sizeof(buff),0);
if(len > 0)
{
printf("client data: %s\n",buff);
send(cfd,buff,len,0);
}
else if(len == 0)
{
printf("断开连接\n");
break;
}
else
{
perror("recv");
break;
}
}
//结束连接
close(fd);
close(cfd);
return 0;
}
客户端:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
int main()
{
//创建通信套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd == -1)
{
perror("socket");
return -1;
}
//连接服务器
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议簇
saddr.sin_port = htons(9999); //端口号 主机转网络字节序
inet_pton(AF_INET,"192.168.212.128",&saddr.sin_addr.s_addr);
int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret == -1)
{
perror("connect");
return -1;
}
//通信
int number = 0;
while(1)
{
//发送数据
char buff[1024];
sprintf(buff,"你好,hello,world,%d...\n",number++);
send(fd,buff,strlen(buff)+1,0);
//接收数据
memset(buff,0,sizeof(buff));
int len = recv(fd,buff,sizeof(buff),0);
if(len > 0)
{
printf("server data: %s\n",buff);
}
else if(len == 0)
{
printf("断开连接\n");
break;
}
else
{
perror("recv");
break;
}
sleep(1);
}
//结束连接
close(fd);
return 0;
}
先启动服务端程序:
再启动客户端:
结果如下: