1>socket(套接字通信)
基于TCP服务器实现:
int main()
{
//1、创建套接字,用于连接使用
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
perror("socket error");
return -1;
}
//设置端口号快速重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
printf("端口快速重用成功\n");
//2、给套接字绑定地址信息
//2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //地址族
sin.sin_port = htons(PORT); //端口号网络字节序
sin.sin_addr.s_addr = inet_addr(IP); //IP地址网络字节序
//2.2 绑定工作
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success _%d_\n", __LINE__);
//3、将套接字设置成监听状态
if(listen(sfd, 128) == -1)
{
perror("listen error");
return -1;
}
printf("listen success _%d_\n", __LINE__);
//4、阻塞等待客户端的连接请求
//4.1 填充要接收的客户端地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //IPv4通信
//客户端的主机地址和端口号就无需写了
//4.2 定义接收客户端的地址信息的大小
socklen_t socklen = sizeof(cin);
//4.3 接收客户端的请求
int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);
if(newfd == -1)
{
perror("accept error");
return -1;
}
printf("有新客户端连接,newfd = %d\n", newfd);
//5、收发数据
char buf[128] = ""; //用于接收数据的缓冲区
while(1)
{
//清空缓冲区
bzero(buf, sizeof(buf));
int ret = recv(newfd, buf, sizeof(buf), 0);
if(ret == -1)
{
perror("recv error");
return -1;
}else if(ret == 0)
{
printf("客户端已经下线\n");
break;
}
printf("[%s:%d] :%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
//将数据连接一个字符后发回去
strcat(buf, "*_*");
if(send(newfd, buf, sizeof(buf), 0) == -1)
{
perror("send error");
return -1;
}
}
//6、关闭套接字
close(newfd); //关闭通信的套接字
close(sfd); //关闭连接的套接字
return 0;
}
基于TCP客户端实现:
int main()
{
//1、创建套接字,用于连接使用
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
//设置端口号快速重用
int reuse = 1;
if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
printf("端口快速重用成功\n");
//2、给套接字绑定地址信息
//2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //地址族
sin.sin_port = htons(PORT); //端口号网络字节序
sin.sin_addr.s_addr = inet_addr(IP); //IP地址网络字节序
//2.2 绑定工作
if(bind(cfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success _%d_\n", __LINE__);
//4、连接服务器
//4.1 填充要连接的服务器地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //IPv4通信
cin.sin_port = htons(PORT); //服务器端口号
cin.sin_addr.s_addr = inet_addr(IP); //服务器的主机地址
//4.2 连接服务器
if(connect(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
{
perror("connect error");
return -1;
}
printf("connect success _%d_\n", __LINE__);
//5、收发数据
char buf[128] = ""; //用于接收数据的缓冲区
while(1)
{
//清空缓冲区
bzero(buf, sizeof(buf));
//从终端上获取数据
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) -1] = '\0';
//发送给服务器端
if(send(cfd, buf, sizeof(buf), 0) == -1)
{
perror("send error");
return -1;
}
printf("发送成功\n");
//接收服务器发来的消息
bzero(buf, sizeof(buf));
int res = recv(cfd, buf, sizeof(buf), 0);
if(res == -1)
{
perror("recv error");
return -1;
}else if(res == 0)
{
printf("服务器已经下线\n");
break;
}
printf("[%s:%d] :%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
}
//6、关闭套接字
close(cfd); //关闭连接的套接字
return 0;
}
2>无名管道
int main()
{
//定义子进程的pid
pid_t pid;
//1、定义管道的文件描述符数组
int pipefd[2] = {0};
//2、创建管道
if(pipe(pipefd) != 0)
{
perror("pipe error");
return -1;
}
//创建子进程
pid = fork();
if(pid < 0)
{
perror("fork error");
return -1;
}else if(pid == 0)
{
//关闭写管道
close(pipefd[1]);
//子进程
char rbuf[128] = "";
while(1)
{
//清空容器内容
memset(rbuf, 0, sizeof(rbuf));
//读取父进程发送的消息
read(pipefd[0], rbuf, sizeof(rbuf));
printf("收到父进程消息:%s\n", rbuf);
if(strcmp(rbuf, "quit") == 0)
{
break;
}
}
//关闭读管道
close(pipefd[0]);
//退出进程
exit(0);
}else
{
//关闭读管道
close(pipefd[0]);
//父进程
char wbuf[128] = "";
while(1)
{
bzero(wbuf, sizeof(wbuf)); //清空容器内容
// printf("请输入>>");
fgets(wbuf, sizeof(wbuf), stdin); //从终端读取一个字符串
wbuf[strlen(wbuf)-1] = '\0'; //将容器中的换行变成'\0'
//将该数据发送给子进程
//3、向管道文件中写数据
write(pipefd[1], wbuf, sizeof(wbuf));
//参数1:要写入的文件描述符
//参数2:要写入数据的起始地址
//参数3:要写入数据的大小
if(strcmp(wbuf, "quit") == 0)
{
break;
}
}
}
wait(NULL); //阻塞回收子进程资源
//关闭写端
close(pipefd[1]);
return 0;
}
3>共享内存
send:
int main()
{
//1、获取key值
key_t key;
if((key = ftok("./", 'k')) == -1)
{
perror("ftok error");
return -1;
}
//2、创建共享内存
int shmid;
if((shmid = shmget(key, 4096, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
//3、映射内存地址
char *addr = shmat(shmid, NULL, 0);
if(addr == (void*)-1)
{
perror("shmat error");
return -1;
}
printf("addr = %p\n", addr); //输出共享内存的地址
//向共享内存中写数据
printf("请输入>>:");
fgets(addr, SIZE, stdin); //直接从终端获取数据到共享内存中
addr[strlen(addr) - 1] = 0;
//4、取消映射
if(shmdt(addr) == -1)
{
perror("shmdt error");
return -1;
}
//5、删除共享内存
//shmctl(shmid, IPC_RMID, NULL);
return 0;
}
recv:
int main()
{
//1、获取key值
key_t key;
if((key = ftok("./", 'k')) == -1)
{
perror("ftok error");
return -1;
}
//2、创建共享内存
int shmid;
if((shmid = shmget(key, 4096, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
//3、映射内存地址
char *addr = shmat(shmid, NULL, 0);
if(addr == (void*)-1)
{
perror("shmat error");
return -1;
}
printf("addr = %p\n", addr); //输出共享内存的地址
//读取共享内存中的内容
printf("共享内存中的内容:%s\n", addr);
//4、取消映射
if(shmdt(addr) == -1)
{
perror("shmdt error");
return -1;
}
//5、删除共享内存
//shmctl(shmid, IPC_RMID, NULL);
return 0;
}