一、套接字创建
1、套接字socket的创建
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
→成功时返回文件描述符,失败时返回-1。
● domain套接字中使用的协议族(Protocol Family)信息。
● type套接字数据传输类型信息。
●protocol 计算机间通信中使用的协议信息。
参数一:domain
参数二:type
面向连接的套接字(SOCK_STREAM)---TCP
面向消息的套接字(SOCK DGRAM)---UDP
参数三:protocol 大部分情况下为0
除非遇到以下这种情况∶
"同一协议族中存在多个数据传输方式相同的协议"
数据传输方式相同,但协议不同。此时需要通过第三个参数具体指定协议信息
示例:
头文件
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
int sock = socket(PF_INET,SOCK_STREAM,0); //IPV4 TCP
2、bind函数
#include<sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
→成功时返回0,失败时返回-1。
参数一:套接字描述符 sockfd
要分配地址信息(IP地址和端口号)的套接字文件描述符。
参数二:存有地址信息的结构体变量地址值 myaddr
网络地址
4字节地址族
IPv4(Internet Protocol version 4)
16字节地址族
IPv6(Internet Protocol version 6)
地址信息的表示
struct sockaddr_in
{
sa_family//地址族(Address Family)
sa_family_t sin_family;// //地址族(Address Family)
uint16_t sin_port; // 16位TCP/UDP端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用
}
该结构体中提到的另一个结构体in_addr定义如下,它用来存放32位IP地址。
struct in_addr
{
In_addr_t s_addr; //32位IPv4地址
};
参数三:第二个结构体变量的长度
一般直接用sizeof第二个参数就行
示例:
if(sock!=-1)
{
stuct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.0.1"); //IP
addr.sin_port = htons(9527); //端口
bind(sock,(struct sockaddr*)&addr,sizeof(addr));
}
3、listen函数
#include <sys/socket.h>
int listen(int sock,int backlog);
→成功时返回0,失败时返回-1。
sock希望进入等待连接请求状态的套接字文件描述符
传递的描述符套接字参数成为服务器端 套接字(监听套接字)。
backlog 连接请求等待队列(Queue)的长度,若为5,则队列长度为5,表示最多使5个连接请求进入队列。
4、accept函数
#include<sys/socket.h>
int accept(int sock,struct sockaddr * addr, socklen_t*addrlen);
→成功时返回创建的套接字文件描述符,失败时返回-1。
5、connect函数
#include<sys/socket.h>
int connect(int sock,struct sockaddr*servaddr, socklen_t addrlen);
→成功时返回0,失败时返回-1。
● sock 客户端套接字文件描述符。
● servaddr 保存目标服务器端地址信息的变量地址值。
●addrlen 以字节为单位传递已传递给第二个结构体参数servaddr的地址变量长度。
二、TCP编程(基础,启动一次服务程序 只服务一个客户端)
基于TCP服务端/客户端的函数调用关系:
1、TCP服务端
最简单的流程 :
服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
void lession60() //服务端
{
int serv_sock, clnt_sock; //创建两个套接字承载变量
struct sockaddr_in serv_addr, clnt_addr; //地址
socklen_t clnt_addr_size; //客户端地址长度
const char* message = "Hello World!\n";
serv_sock = socket(PF_INET, SOCK_STREAM, 0); //IPv4 TCP 创建套接字
if (serv_sock < 0) //发生错误
{
std::cout << "create socket failed!\n" << std::endl;
return;
}
memset(&serv_addr, 0, sizeof(serv_addr)); //地址清0
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //本机地址
serv_addr.sin_port = htons(9527); //端口9527
int ret = bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)); //绑定套接字
if (ret == -1)
{
std::cout << "bind failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
ret = listen(serv_sock, 3); //开始监听,队列3
if(ret==-1)
{
std::cout << "listen failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
// accept 客户端连接 卡在此处!!!!!!
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
{
std::cout << "accept failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
//成功连接客户端
//开始发信息给客户端
ssize_t len = write(clnt_sock, message, strlen(message));
//注意上下两个ssize_t 如果用int会有warning!!
if (len != (ssize_t)strlen(message))
{
std::cout << "write failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
close(clnt_sock); //关闭客户端
close(serv_sock); //关闭服务端
}
2、TCP客户端
客户端代码:
#include <sys/wait.h>
void lession62()
{
pid_t pid = fork(); //开一个子进程
if (pid == 0) //子进程
{
//开启客户端
sleep(1);
int client = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
struct sockaddr_in servaddr; //服务器的地址
memset(&servaddr, 0, sizeof(servaddr)); //地址清0
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(9527);
int ret = connect(client, (struct sockaddr*)&servaddr, sizeof(servaddr)); //连接服务器
if (ret == 0)
{
char buffer[256] = "";
read(client, buffer, sizeof(buffer));
std::cout << buffer;
}
close(client);
std::cout << "client done!" << std::endl;
}
else if (pid > 0) //主进程
{
//开启服务端
lession60();
int status = 0;
wait(&status); //头文件 sys/wait.h
}
else
{
std::cout << "fork failed!" << pid << std::endl;
}
}
int main(int argc, char* argv[])
{
lession62();
return 0;
}
三、迭代服务器
迭代服务器比较原始,原型为:
while(1)
{
new_fd = 服务器accept客户端的连接(new_fd = accept(listenfd, XX, XX))
逻辑处理
在这个new_fd上给客户端发送消息
关闭new_fd
}
代码:
//迭代服务器
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
void lession63_()
{
int serv_sock, clnt_sock; //创建两个套接字承载变量
struct sockaddr_in serv_addr, clnt_addr; //地址
socklen_t clnt_addr_size; //客户端地址长度
//const char* message = "Hello World!\n";
serv_sock = socket(PF_INET, SOCK_STREAM, 0); //IPv4 TCP 创建套接字
if (serv_sock < 0) //发生错误
{
std::cout << "create socket failed!\n" << std::endl;
return;
}
memset(&serv_addr, 0, sizeof(serv_addr)); //地址清0
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //本机地址
serv_addr.sin_port = htons(9521); //端口9523
int ret = bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //绑定套接字
if (ret == -1)
{
std::cout << "bind failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
ret = listen(serv_sock, 3); //开始监听,队列3
if (ret == -1)
{
std::cout << "listen failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
char buffer[1024]{};
while (1)
{
memset(buffer, 0, sizeof(buffer));
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
// accept 客户端连接
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
{
std::cout << "accept failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
//成功连接客户端
//开始发信息给客户端
//ssize_t len = write(clnt_sock, message, strlen(message));
ssize_t len = read(clnt_sock, buffer, sizeof(buffer));
//注意上下两个ssize_t 如果用int会有warning!!
if (len != (ssize_t)strlen(buffer))
{
std::cout << "read failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
std::cout << buffer;
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
len = write(clnt_sock, buffer, strlen(buffer));
close(clnt_sock); //关闭客户端
}
close(serv_sock); //关闭服务端
}
void runClient()
{
int client = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
struct sockaddr_in servaddr; //服务器的地址
memset(&servaddr, 0, sizeof(servaddr)); //地址清0
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(9521);
int ret = connect(client, (struct sockaddr*)&servaddr, sizeof(servaddr)); //连接服务器
if (ret == 0)
{
char buffer[256] = "hello,here is client!\n";
write(client, buffer, strlen(buffer));
memset(buffer, 0, sizeof(buffer));
read(client, buffer, sizeof(buffer));
std::cout << buffer;
}
close(client);
std::cout << "client done!" << std::endl;
}
void lession63()
{
pid_t pid = fork(); //开一个子进程
if (pid == 0) //子进程
{
//开启客户端
sleep(1);
runClient();
runClient();
}
else if (pid > 0) //主进程
{
//开启服务端
lession63_();
int status = 0;
wait(&status); //头文件 sys/wait.h
}
else
{
std::cout << "fork failed!" << pid << std::endl;
}
}
int main(int argc, char* argv[])
{
/*lession62();*/
lession63();
return 0;
}
四、回声服务器
1、基础部分
服务器接收到客户端的数据,直接把客户端的数据发回客户端,代码:
//头文件
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
客户端:
void run_client64() //客户端
{
int client = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
struct sockaddr_in servaddr; //服务器的地址
memset(&servaddr, 0, sizeof(servaddr)); //地址清0
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(9527);
int ret = connect(client, (struct sockaddr*)&servaddr, sizeof(servaddr)); //连接服务器
while (ret == 0)
{
//char buffer[256]{ "hello,here is client!\n" };
//write(client, buffer, strlen(buffer)); //常量 写死
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
/*不用常量,可以输入的写法*/
char buffer[256] = "";
fputs("Input message(Q/q to quit):", stdout); //提示输出,按q退出
fgets(buffer, sizeof(buffer), stdin); //输入
if ( (strcmp(buffer, "q\n") == 0) || (strcmp(buffer, "Q\n") == 0) )
{
break; //退出循环,准备关闭客户端
}
write(client, buffer, strlen(buffer));
/* */
memset(buffer, 0, sizeof(buffer));
read(client, buffer, sizeof(buffer));
std::cout << "from server:" << buffer;
}
close(client);
std::cout << "client done!" << std::endl;
}
服务端:
void server64() //服务端
{
int serv_sock, client; //创建两个套接字承载变量
struct sockaddr_in serv_addr, clnt_addr; //地址
socklen_t clnt_addr_size; //客户端地址长度
serv_sock = socket(PF_INET, SOCK_STREAM, 0); //IPv4 TCP 创建套接字
if (serv_sock < 0) //发生错误
{
std::cout << "create socket failed!\n" << std::endl;
return;
}
memset(&serv_addr, 0, sizeof(serv_addr)); //地址清0
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //本机地址
serv_addr.sin_port = htons(9527); //端口9523
int ret = bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //绑定套接字
if (ret == -1)
{
std::cout << "bind failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
ret = listen(serv_sock, 3); //开始监听,队列3
if (ret == -1)
{
std::cout << "listen failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
char buffer[1024]{};
for (int i = 0; i < 2; i++) //服务器不是无限制的 只能服务两个客户端后结束
{
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
// accept 客户端连接
client = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (client == -1)
{
std::cout << "accept failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
//成功连接客户端
/* printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
//开始从客户端读信息
memset(buffer, 0, sizeof(buffer));
ssize_t len = read(client, buffer, sizeof(buffer));
if (len <= 0)
{
std::cout << "read failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
else
{
std::cout <<"from client:"<< buffer << std::endl;
}
//开始发信息给客户端
len = write(client, buffer, len); // 第二个len就是strlen(buffer)
//注意上下两个ssize_t 如果用int会有warning!!
if (len != (ssize_t)strlen(buffer))
{
std::cout << "write failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
else
{
std::cout << "write to client:" << buffer << std::endl;
}
*/
/*一种精简的写法*/
memset(buffer, 0, sizeof(buffer));
ssize_t len{};
while ( ( len = read(client, buffer, sizeof(buffer)) )>0 ) //读到了
{
//std::cout << "from client:" << buffer << std::endl; //输出内容
//开始发信息给客户端
len = write(client, buffer, len); // 第二个len就是strlen(buffer)
//注意上下两个ssize_t 如果用int会有warning!!
if (len != (ssize_t)strlen(buffer))
{
std::cout << "write failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
memset(buffer, 0, sizeof(buffer));
}
/*if (len <= 0) //没读到
{
std::cout << "read failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}*/ //只是一个客户端出问题,没必要关闭服务器,也没必要return
close(client); //关闭客户端
}
close(serv_sock); //关闭服务端
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
}
服务端客户端联调:
void lession64()
{
pid_t pid = fork(); //开一个子进程
if (pid == 0) //子进程
{
//开启服务器
server64();
}
else if (pid > 0) //主进程
{
//开启客户端
sleep(1);
for (int i = 0; i < 2; ++i)
{
run_client64();
}
int status = 0;
wait(&status); //头文件 sys/wait.h
}
else
{
std::cout << "fork failed!" << pid << std::endl;
}
}
int main(int argc, char* argv[])
{
lession64();
return 0;
}
2、存在的问题及解决方案
回收服务器存在的问题:
定义的buffer为1024, 字符串太长,需要分2个或多个数据包发送时,返回的len会不对。
完美解决以上问题:
修改后:(多次write和read,方便打包发送)
void run_client64() //客户端
{
int client = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
struct sockaddr_in servaddr; //服务器的地址
memset(&servaddr, 0, sizeof(servaddr)); //地址清0
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(9527);
int ret = connect(client, (struct sockaddr*)&servaddr, sizeof(servaddr)); //连接服务器
while (ret == 0)
{
//char buffer[256]{ "hello,here is client!\n" };
//write(client, buffer, strlen(buffer)); //常量 写死
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
/*不用常量,可以输入的写法*/
char buffer[256] = "";
fputs("Input message(Q/q to quit):", stdout); //提示输出,按q退出
fgets(buffer, sizeof(buffer), stdin); //输入
if ((strcmp(buffer, "q\n") == 0) || (strcmp(buffer, "Q\n") == 0))
{
break; //退出循环,准备关闭客户端
}
size_t len = strlen(buffer); //!!!!!!!!!!!修改的
size_t send_len{ 0 }; //!!!!!!!!!!!
while (send_len < len) //!!!!!!!!!!!以下!
{
ssize_t ret = write(client, buffer + send_len, len - send_len);
if (ret <= 0)
{
fputs("write failed!\n", stdout);
close(client);
std::cout << "client done!" << std::endl;
return;
}
send_len += (size_t)ret;
}
/* */
memset(buffer, 0, sizeof(buffer));
size_t read_len = 0;
while (read_len < len)
{
ssize_t ret = read(client, buffer + read_len, len-read_len);
if (ret <= 0)
{
fputs("read failed!\n", stdout);
ret = -1;
close(client);
std::cout << "client done!" << std::endl;
return;
}
read_len += (size_t)ret;
}
std::cout << "from server:" << buffer;
}
close(client);
std::cout << "client done!" << std::endl;
}
五、回声服务器实战:计算器的网络实现
要求:
1、客户端连接到服务器端后以1字节整数形式传递待算数字个数。
2、客户端向服务器端传递的每个整数型数据占用4字节。
3、传递整数型数据后接着传递运算符。运算符信息占用1字节。
选择字符+、-、*之一传递。
4、服务器端以4字节整数型向客户端传回运算结果。
5、客户端得到运算结果后终止与服务器端的连接。
代码:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
int calculate(int count, int oprand[], char op)
{
int result{0};
switch (op)
{
case'+':
for (int i=0;i<count;i++)
{
result += oprand[i];
}
break;
case'-':
for (int i = 0; i < count; i++)
{
result -= oprand[i];
}
break;
case'*':
result = 1;
for (int i = 0; i < count; i++)
{
result *= oprand[i];
}
break;
default:
break;
}
return result;
}
void server66()
{
int serv_sock, client; //创建两个套接字承载变量
struct sockaddr_in serv_addr, clnt_addr; //地址
socklen_t clnt_addr_size; //客户端地址长度
serv_sock = socket(PF_INET, SOCK_STREAM, 0); //IPv4 TCP 创建套接字
if (serv_sock < 0) //发生错误
{
std::cout << "create socket failed!\n" << std::endl;
return;
}
memset(&serv_addr, 0, sizeof(serv_addr)); //地址清0
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //本机地址
serv_addr.sin_port = htons(9523); //端口9523
int ret = bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //绑定套接字
if (ret == -1)
{
std::cout << "bind failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
ret = listen(serv_sock, 3); //开始监听,队列3
if (ret == -1)
{
std::cout << "listen failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
char buffer[1024]{};
for (int i = 0; i < 2; i++) //服务器不是无限制的 只能服务两个客户端后结束
{
//printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
// accept 客户端连接
client = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (client == -1)
{
std::cout << "accept failed!\n" << std::endl;
close(serv_sock); //!!!!! 套接字已经启用 需要先关闭才能return
return;
}
//成功连接客户端
/*一种精简的写法*/
memset(buffer, 0, sizeof(buffer));
ssize_t len{};
len = read(client, buffer, 1);
int result{};
if (len > 0)
{ //必须&因为16进制转无符号前面会填满1
for (unsigned i = 0; i < ((unsigned)buffer[0] & 0xFF); i++)
{
read(client, buffer + 1 + i * 4, 4);
}
read(client, buffer + 1 + ((unsigned)buffer[0] & 0xFF)*4, 1);
result = calculate(((int)buffer[0] & 0xFF), (int*)(buffer + 1),
buffer[1 + ((unsigned)buffer[0] & 0xFF) * 4]);
write(client, &result, 4); //发回客户端
}
close(client); //关闭客户端
}
close(serv_sock); //关闭服务端
printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
}
void run_client66()
{
int client = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
struct sockaddr_in servaddr; //服务器的地址
memset(&servaddr, 0, sizeof(servaddr)); //地址清0
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(9523);
int ret = connect(client, (struct sockaddr*)&servaddr, sizeof(servaddr)); //连接服务器
char buffer[1024]{};
while (ret == 0)
{
//printf("%s(%d):%s\n", __FILE__, __LINE__, __FUNCTION__);
/*不用常量,可以输入的写法*/
fputs("operand count:", stdout); //提示要输入的操作数的数量
int opnd_cnt{ 0 }; //变量保存操作数的数量
scanf("%d", &opnd_cnt);
if (opnd_cnt <= 1 && opnd_cnt >= 256)
{
fputs("opnd_cnt error,too small or too big!\n", stdout);
close(client);
std::cout << "client done!" << std::endl;
return;
}
buffer[0] = (char)opnd_cnt; //服务器此处要解释为无符号
for (int i = 0; i < opnd_cnt; ++i)
{ //!!!!!!!!!!!!!!!!!!!!!
scanf("%d", buffer + 1 + i * 4); //* **** **** 一个是符号1字节 后面是数字4字节
} //!!!32位环境int是4字节!!64位为8字节!!!
fgetc(stdin); //上面输入完需要加一个换行符 但不取!! 很细节
fputs("Operator:", stdout); //提示输入操作符
buffer[1 + opnd_cnt * 4] = (char)fgetc(stdin);
size_t len = opnd_cnt * 4 + 2; //2 是 前面一个字符 后面一个字符
size_t send_len{ 0 };
while (send_len < len)
{
ssize_t ret = write(client, buffer + send_len, len - send_len);
if (ret <= 0)
{
fputs("write failed!\n", stdout);
close(client);
std::cout << "client done!" << std::endl;
return;
}
send_len += (size_t)ret;
}
/* */
memset(buffer, 0, sizeof(buffer));
size_t read_len = 0;
while (read_len < 4) //最后写的是4个字节,因此读4个字节即可
{
ssize_t ret = read(client, buffer + read_len, len - read_len);
if (ret <= 0)
{
fputs("read failed!\n", stdout);
ret = -1;
close(client);
std::cout << "client done!" << std::endl;
return;
}
read_len += (size_t)ret;
}
printf("from server:%d\n", * (int*)buffer);
}
close(client);
std::cout << "client done!" << std::endl;
}
void lession66()
{
pid_t pid = fork(); //开一个子进程
if (pid == 0) //子进程
{
//开启服务器
server66();
}
else if (pid > 0) //主进程
{
//开启客户端
sleep(1);
for (int i = 0; i < 2; ++i)
{
run_client66();
}
int status = 0;
wait(&status); //头文件 sys/wait.h
}
else
{
std::cout << "fork failed!" << pid << std::endl;
}
}
int main(int argc, char* argv[])
{
lession66();
return 0;
}