客户端逻辑(不要绑定端口号)
1.用户输入数据,从标准输入输入一个字符串
2.把这个字符串发送给服务器
3.从服务器读取并返回结果
4.把响应写到标准输出上
服务器逻辑(绑定端口号)
1.启动(初始化)
2.进入死循环(事件循环)
a)从socket中读取请求(Request)
b)根据Request的内容计算生成Response
c)把Response响应写回socket
服务器server.c
int main()
{
//创建socket IPV4 TCP 指定协议 不关心置0
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
}
//定义两个addr_in 结构体
struct sockaddr_in server_socket;
struct sockaddr_in client_socket;
//把server_socket置为零且包括‘\0’
bzero(&server_socket,sizeof(server_socket));
//初始化server_socket
server_socket.sin_family = AF_INET;
server_socket.sin_port = htons(_PORT_);//宏_PORT_被define成某个端口号
//网络地址为INADDR_ANY,这个宏可以表示本地的任意IP地址
//因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这个设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址;
server_socket.sin_addr.s_addr = htonl(INADDR_ANY);//htohl表示主机字节序转网络字节序
//将服务器的ip和端口号进行绑定
if(bind(sock,(struct sockaddr *)&server_socket,sizeof(struct sockaddr_in)) < 0)
{
printf("bind error,error code is %d,error string is :%s\n",errno,strerror(errno));
close(sock);
return 1;
}
//绑定成功开始进入监听模式,_BACKLOG_ 正处于三次握手中的sock 定义为10
if(listen(sock,_BACKLOG_) < 0)
{
printf("listen error,error code is %d,error string is %s\n",errno,strerror(errno));
close(sock);
return 2;
}
printf("bind and listen success,wait accept...\n");
while(1)
{
socklen_t len = 0;
//accept为阻塞式等待,若想改为非阻塞,可考虑添加IO多路复用机制,select,poll,epoll
//三次握⼿完成后, 服务器调⽤accept()接受连接
//若成功返回一个新的sock,专门用于与已连接的客户端通信
int client_sock = accept(sock,(struct sockaddr *)&client_socket,&len);
if(client_sock < 0)
{
printf("accept error, error is %d,errstring is %s\n",errno,strerror(errno));
close(sock);
return 3;
}
//开辟出一块新的缓存区用于存放IP地址
char buf_ip[INET_ADDRSTRLEN];
memset(buf_ip,'\0',sizeof(buf_ip));
// inet_ntop函数将用于网络传输的数值格式 转化为 点分十进制的ip地址 适用于IPV4,IPV6
inet_ntop(AF_INET,&client_socket.sin_addr,buf_ip,sizeof(buf_ip));
while(1)
{
//建立连接之后两端开始进行数据的交互式传输
//创建缓存区并清空
char buf[1024];
memset(buf,'\0',sizeof(buf));
//从sock中读取来自客户端的数据进buf
read(client_sock,buf,sizeof(buf));
//清空buf缓存区,往buf里面写服务器端响应
memset(buf,'\0',sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
//再把buf的数据往sock发送
write(client_sock,buf,strlen(buf)+1);//在这里strlen(buf)+1和sizeof(buf)的区别
printf("please wait...\n");
}
}
close(sock);
return 0;
}
客户端client.c
int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("usage :client IP\n");
return 1;
}
//存放命令行参数(ip地址)
char *str = argv[1];
char buf[1024];
memset(buf,'\0',sizeof(buf));
// 定义一个addr_in结构体作为服务器端的标识
struct sockaddr_in server_sock;
//创建一个sock
int sock = socket(AF_INET,SOCK_STREAM,0);
//初始化server_sock为0
bzero(&server_sock,sizeof(server_sock));
server_sock.sin_family = AF_INET;
//把点分十进制整型转为网络字节序
inet_pton(AF_INET,SERVER_IP,&server_sock.sin_addr);
//主机字节序转为网络字节序
server_sock.sin_port = htons(SERVER_PORT);
//向服务器端发起连接请求
int ret = connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock));
if(ret < 0)
{
printf("connect failed...,errno is %d,errstring is %s\n",errno,strerror(errno));
}
printf("connect is success...\n");
//进入事件循环
while(1)
{
//从标准输入写数据进buf
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
write(sock,buf,sizeof(buf));
//strncasecmp为忽略大小写的比较, 如果发现
if(strncasecmp(buf,"quit",4) == 0)
{
//如果发现用户输入quit,则退出
printf("quit\n");
break;
}
read(sock,buf,sizeof(buf));
}
close(sock);
return 0;
}