套接字( socket )也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
(1)服务器:server
创建套接字 socket( )
填充服务器网络信息结构体 sockaddr_in
将套接字与服务器网络信息结构体绑定 bind( )
将套接字设置为被动监听模式 listen( )
阻塞等待客户端的连接请求 accept( )
进行通信 recv( )/send( ) (read( )/write( ))
#include //printf
#include //inet_addr htons
#include
#include //socket bind listen accept connect
#include //sockaddr_in
#include //exit
#include //close
#include
#define N 128
#define errlog(errmsg) do{perror(errmsg);\
printf("%s -- %s -- %d\n", __FILE__, __func__, __LINE__);\
exit(1);\
}while(0)
int main(int argc, const char *argv[])
{
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
char buf[N] = {};
ssize_t bytes;
if(argc < 3)
{
fprintf(stderr, "Usage: %s \n" , argv[0]);
exit(1);
}
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
errlog("fail to socket");
}
//第二步:填充服务器网络信息结构体
//inet_addr:将点分十进制ip地址转化为网络字节序的整型数据
//htons:将主机字节序转化为网络字节序
//atoi:将数字型字符串转化为整型数据
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//第三步:将套接字与服务器网络信息结构体绑定
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
errlog("fail to bind");
}
//第四步:将套件字设置为被动监听状态
if(listen(sockfd, 5) < 0)
{
errlog("fail to listen");
}
//第五步:阻塞等待客户端的连接请求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
errlog("fail to accept");
}
//服务器知道客户端的信息
printf("%s --> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
while(1)
{
if((bytes = recv(acceptfd, buf, N, 0)) < 0)
{
errlog("fail to recv");
}
else if(bytes == 0)
{
printf("NO DATA\n");
exit(1);
}
else
{
if(strncmp(buf, "quit", 4) == 0)
{
printf("The client is quited\n");
break;
}
printf("client: %s\n", buf);
strcat(buf, " *_*");
if(send(acceptfd, buf, N, 0) < 0)
{
errlog("fail to send");
}
}
}
close(acceptfd);
close(sockfd);
return 0;
}
(2)客户端:client
创建套接字 socket( )
填充服务器网络信息结构体 sockaddr_in
发送客户端的连接请求 connect( )
进行通信 send( )/recv( )
#include //printf
#include //inet_addr htons
#include
#include //socket bind listen accept connect
#include //sockaddr_in
#include //exit
#include //close
#include
#define N 128
#define errlog(errmsg) do{perror(errmsg);\
printf("%s -- %s -- %d\n", __FILE__, __func__, __LINE__);\
exit(1);\
}while(0)
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
char buf[N] = {};
if(argc < 3)
{
fprintf(stderr, "Usage: %s \n" , argv[0]);
exit(1);
}
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
errlog("fail to socket");
}
//第二步:填充服务器网络信息结构体
//inet_addr:将点分十进制ip地址转化为网络字节序的整型数据
//htons:将主机字节序转化为网络字节序
//atoi:将数字型字符串转化为整型数据
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
#if 0
//客户端可以自己指定信息
struct sockaddr_in clientaddr;
clientaddr.sin_family = AF_INET;
clientaddr.sin_addr.s_addr = inet_addr(argv[3]);
clientaddr.sin_port = htons(atoi(argv[4]));
if(bind(sockfd, (struct sockaddr *)&clientaddr, addrlen) < 0)
{
errlog("fail to bind");
}
#endif
//第三步:发送客户端的连接请求
if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
{
errlog("fail to connect");
}
while(1)
{
fgets(buf, N, stdin);
buf[strlen(buf) - 1] = '\0';
if(send(sockfd, buf, N, 0) < 0)
{
errlog("fail to send");
}
if(strncmp(buf, "quit", 4) == 0)
{
printf("The client is quited\n");
break;
}
if(recv(sockfd, buf, N, 0) < 0)
{
errlog("fail to recv");
}
printf("server: %s\n", buf);
}
close(sockfd);
return 0;
}