客户端流程:
- 创建并打开套接字 socket
- 绑定IP地址和端口号 bind
- 请求连接---三次握手 connect
- 收发消息 read/write recv/send
- 关闭套接字 close
服务器流程:
- 创建并打开套接字 socket
- 绑定IP地址和端口号 bind
- 创建监听队列 listen
- 等待并建立连接 accept
- 收发消息 read/write recv/send
- 关闭套接字 close
客户端,服务器端 采用父子进程分别实现写操作和读操作,实现自由收发数据功能。
/* 服务器端 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <stdlib.h>
void sigFunc(int signum)
{
if(signum == SIGCHLD)
{
waitpid(-1,NULL,WNOHANG);
printf("子进程退出\n");
exit(0);
}
}
int main()
{
//创建并打开套接字
int sockFd = socket(PF_INET, SOCK_STREAM, 0);
if(sockFd < 0)
{
perror("socket error!");
return -1;
}
printf("socket ok!\n");
//绑定IP地址和端口号
struct sockaddr_in servAddr = {0};//服务器的地址信息
servAddr.sin_family = PF_INET;
servAddr.sin_port = htons(10086);
//"0.0.0.0"当前主机IP是多少就绑定多少
servAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
int ret = bind(sockFd, (struct sockaddr *)&servAddr, sizeof(servAddr));
if(ret < 0)
{
perror("bind error!");
close(sockFd);
return -1;
}
printf("bind ok!\n");
//创建监听队列
//socket从主动变成被动
ret = listen(sockFd, 10);
if(ret < 0)
{
perror("listen error!");
close(sockFd);
return -1;
}
printf("listening......\n");
//等待并建立连接
struct sockaddr_in cliAddr = {0};
socklen_t len = sizeof(cliAddr);
int connFd = accept(sockFd, (struct sockaddr *)&cliAddr, &len);
if(connFd < 0)
{
perror("accept error!");
close(sockFd);
return -1;
}
printf("IP:%s, PORT:%d accept ok\n", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
//接收消息
char buf[100] = {0};
pid_t pid = fork();
if(pid < 0)
{
printf("fork error !\n");
close(sockFd);
return -1;
}
else if(pid == 0)
{
while(1)
{
memset(buf, 0, sizeof(buf));
printf("server:");
gets(buf);
if(0 == strcmp(buf, "quit"))
{
break;
}
ret = send(connFd, buf, sizeof(buf), 0);
if(ret < 0)
{
perror("send error!");
close(connFd);
close(sockFd);
return -1;
}
}
}
else if(pid > 0)
{
signal(SIGCHLD,sigFunc);
while(1)
{
memset(buf, 0, sizeof(buf));
ret = recv(connFd, buf, sizeof(buf), 0);
if(ret < 0)
{
perror("recv error!");
close(sockFd);
close(connFd);
return -1;
}
else if(0 == ret||0 == strcmp(buf,"quit"))
{
//客户端关闭了
break;
}
printf("recv:%s\n", buf);
}
}
//关闭套接字
close(sockFd);
close(connFd);
return 0;
}
/* 客户端 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <stdlib.h>
void sigFunc(int signum)
{
if(signum == SIGCHLD)
{
waitpid(-1,NULL,WNOHANG);
exit(0);
}
}
int main()
{
char servIp[20] = {0};
printf("请输入服务器IP:");
gets(servIp);
//创建并打开套接字
int sockFd = socket(PF_INET, SOCK_STREAM, 0);
if(sockFd < 0)
{
perror("socket error!");
return -1;
}
printf("socket ok!\n");
#if 0
//绑定地址信息
//绑定客户端自己的地址信息
struct sockaddr_in cliAddr = {0};
cliAddr.sin_family = PF_INET;
cliAddr.sin_port = htons(9999);
cliAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = bind(sockFd, (struct sockaddr *)&cliAddr, sizeof(cliAddr));
if(ret < 0)
{
perror("bind error!");
close(sockFd);
return -1;
}
printf("bind ok!\n");
#endif
//连接服务器
struct sockaddr_in servAddr = {0};//服务器的地址信息
servAddr.sin_family = PF_INET;
servAddr.sin_port = htons(10086);
servAddr.sin_addr.s_addr = inet_addr(servIp);
int ret = connect(sockFd, (struct sockaddr *)&servAddr, sizeof(servAddr));
if(ret < 0)
{
perror("connect error!");
close(sockFd);
return -1;
}
printf("connect ok!\n");
//发送消息
char buf[100] = {0};
pid_t pid = fork();
if(pid < 0)
{
printf("fork error !\n");
close(sockFd);
return -1;
}
else if(pid == 0)
{
while(1)
{
memset(buf, 0, sizeof(buf));
ret = recv(sockFd, buf, sizeof(buf), 0);
if(ret < 0)
{
perror("recv error!");
close(sockFd);
return -1;
}
else if(0 == ret)
{
//关闭了
break;
}
printf("recv:%s\n", buf);
}
}
else if(pid > 0)
{
signal(SIGCHLD,sigFunc);
while(1)
{
memset(buf, 0, sizeof(buf));
printf("client:");
gets(buf);
if(0 == strcmp(buf, "quit"))
{
break;
}
ret = send(sockFd, buf, sizeof(buf), 0);
if(ret < 0)
{
perror("send error!");
close(sockFd);
return -1;
}
}
}
//关闭套接字
close(sockFd);
return 0;
}