如上图所示,在tcp通信中,客户端和服务器端的通信模型。
服务器端首先需要创建监听套接字(socket),创建监听套接字之后,绑定(bind)需要监听的sockaddr,然后开始监听(listen),监听之后就是等待客户端发起连接(accept),接受到客户端发起的连接之后,然后和客户端通信(recv,send)。客户端这一边,首先就是创建通信socket,然后通过connect函数向服务器发起连接,连接成功之后就可以和服务器通信了(send,recv)。
详情代码如下:
客户端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <resolv.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <signal.h>
const int MAXBUF=1000;
// 信号处理函数,需要添加signal.h
void sig_handler(int signo)
{
if(signo == SIGINT)
{
printf("server close\n");
exit(1);
}
}
int main()
{
// 创建socket
// 第一个参数,AF_INET,表示ipv4,AF_INET6表示使用ipv6,AF_UNIX暂时不讲,这两个比较少见
//SOCK_STREAM, 表示使用tcp协议,SOCK_DGRAM使用udp协议,还有SOCK_RAW,SOCK_SEQPACKET等,详情可以参见man
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in dst;
dst.sin_family = AF_INET; //使用Ipv4
dst.sin_port = htons(10567); // 将端口号10567抓换成网络字节序
dst.sin_addr.s_addr = htonl(0x7f000001);//将ip地址转换成网络字节序
int ret = 0;
//向服务器发起连接
ret = connect(socketfd, (struct sockaddr*)&dst, sizeof(sockaddr_in));
if(ret != 0)
{
printf("connect failed\n");
close(socketfd);
socketfd = -1;
}
char buf[MAXBUF] = {0};
int i = 0;
memset(buf, 0, sizeof(buf));
sprintf(buf, "i = %d, socket = %d, time = %lu", i, socketfd, clock());
printf("send buffer = [%s]\n", buf);
//向服务器端发送数据,
send(socketfd, buf, strlen(buf), 0);
memset(buf, 0, sizeof(buf));
// 接收服务器返回的数据
ret = recv(socketfd, buf, sizeof(buf), 0);
if(ret == 0)
{
printf("error find\n");
//break;
}
else
{
printf("recv len = %d, i = %d, socket = %d,\n", ret, i, socketfd);
printf("recv buffer = [%s]\n", buf);
}
close(socketfd);
socketfd = -1;
return 0;
}
服务器端代码如下
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
const unsigned int MAXBUF = 1000;
void sig_handler(int signo)
{
if(signo == SIGINT)
{
printf("server close\n");
exit(1);
}
}
int main()
{
// 添加信号处理函数,捕获SIGINT(ctrl+c)信号
if(signal(SIGINT, sig_handler) == SIG_ERR)
{
perror("signal error\n");
exit(1);
}
// 创建socket,ipv4,tcp协议
int listenFd = socket(AF_INET, SOCK_STREAM, 0);
if(listenFd <= 0)
{
printf("create tcp socket failed\n");
return -1;
}
// 绑定本地ip和端口以及设置ipv4,将ip和端口转化成网络字节序
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(10567);
local.sin_addr.s_addr = INADDR_ANY;// htonl(0x7f000001);
int ret = 0;
ret = bind(listenFd, (struct sockaddr*)&local, sizeof(sockaddr));
if(ret != 0)
{
printf("bind ret = %d\n", ret);
return -2;
}
// 开启监听
listen(listenFd, 10000);
sockaddr_in src;
unsigned int srcLength = sizeof(sockaddr_in);
char buffer[MAXBUF] = {0};
while(1)
{
//阻塞方式,当客户端发起连接的时候,会返回连接的socket
int fd = accept(listenFd, (struct sockaddr*)&src, &srcLength);
if(fd <= 0)
{
break;
}
else
{
memset(buffer, 0, sizeof(buffer));
recv(fd, buffer, MAXBUF, 0);
printf("server recv buffer = %s\n", buffer);
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "server send fd = %d, time = %lu\n", fd, clock());
send(fd, buffer, strlen(buffer), 0);
}
sleep(2);
}
close(listenFd);
listenFd = -1;
return 0;
}