服务端
#include<stdio.h>
#include <string.h>
#include <unistd.h> //系统调用的接口
#include <netdb.h> //网络有关
#include <sys/types.h> //linux相关基本数据类型
#include <sys/socket.h>
#include <arpa/inet.h>
class CTcpServer{
public:
int m_listenfd; //监听socket
int m_clientfd; // 监听之后接受连接的socket
CTcpServer(){
m_listenfd = 0; //初始化为0
}
~CTcpServer(){
close(m_listenfd);
close(m_clientfd);
}
bool InitServer(int port){
m_listenfd = socket(AF_INET, SOCK_STREAM, 0);//第三个表示协议,0表示默认tcp协议
struct sockaddr_in Serveraddr;
//先初始化再赋值
memset(&Serveraddr, 0, sizeof(Serveraddr));
Serveraddr.sin_family = AF_INET;
Serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
Serveraddr.sin_port = htons(port);
if(bind(m_listenfd, (struct sockaddr *)&Serveraddr, sizeof(Serveraddr) ) != 0){
printf("绑定失败\n");
close(m_listenfd);
return false;
}
if(listen(m_listenfd, 5) !=0){
printf("监听失败\n");
close(m_listenfd);
return false;
}
return true;
}
bool Accept(){
struct sockaddr_in clientaddr;
//if((m_clientfd = accept(m_listenfd, (struct sockaddr *)&clientaddr, sizeof(clientaddr))) <= 0)
if((m_clientfd = accept(m_listenfd, 0, 0)) <= 0) //为什么是0,0
return false;
return true;
}
void CloseClient(){
close(m_clientfd);
return ;
}
void CloseListen(){
close(m_listenfd);
return ;
}
};
CTcpServer TcpServer;
int main(){
if(TcpServer.InitServer(5001) == false){
printf("服务端初始化失败\n");
return -1;
}
while(1){
if(TcpServer.Accept() == false) continue;
int pid = fork();
if(pid != 0){
TcpServer.CloseClient();
continue;
}
else{
TcpServer.CloseListen();
printf("客户端已连接\n");
char buffer[1024];
while(1){
memset(buffer, 0, sizeof(buffer));//表示动态分配内存的大小, 比如指针指向的数组是4
if(recv(TcpServer.m_clientfd ,buffer, sizeof(buffer), 0 ) <= 0) break;//实际的长度
printf("接收:%s\n", buffer);
strcpy(buffer, "OK");
if(send(TcpServer.m_clientfd ,buffer, strlen(buffer), 0) <= 0) break;
printf("发送:%s\n", buffer);
}
}
printf("客户端已经断开\n");
return 0;
}
}
客户端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// TCP客户端类
class CTcpClient
{
public:
int m_sockfd;
CTcpClient();
// 向服务器发起连接,serverip-服务端ip,port通信端口
bool ConnectToServer(const char *serverip,const int port);
// 向对端发送报文
int Send(const void *buf,const int buflen);
// 接收对端的报文
int Recv(void *buf,const int buflen);
~CTcpClient();
};
int main()
{
CTcpClient TcpClient;
// 向服务器发起连接请求
if (TcpClient.ConnectToServer("192.168.23.128",5001)==false)
{ printf("TcpClient.ConnectToServer(\"172.16.0.15\",5051) failed,exit...\n"); return -1; }
char strbuffer[1024];
for (int ii=0;ii<5;ii++)
{
memset(strbuffer,0,sizeof(strbuffer));
sprintf(strbuffer,"这是第%d个超级女生,编号%03d。",ii+1,ii+1);
if (TcpClient.Send(strbuffer,strlen(strbuffer))<=0) break;
printf("发送:%s\n",strbuffer);
memset(strbuffer,0,sizeof(strbuffer));
if (TcpClient.Recv(strbuffer,sizeof(strbuffer))<=0) break;
printf("接收:%s\n",strbuffer);
sleep(1); // sleep一秒,方便观察程序的运行。
}
}
CTcpClient::CTcpClient()
{
m_sockfd=0; // 构造函数初始化m_sockfd
}
CTcpClient::~CTcpClient()
{
if (m_sockfd!=0) close(m_sockfd); // 析构函数关闭m_sockfd
}
// 向服务器发起连接,serverip-服务端ip,port通信端口
bool CTcpClient::ConnectToServer(const char *serverip,const int port)
{
m_sockfd = socket(AF_INET,SOCK_STREAM,0); // 创建客户端的socket
struct hostent* h; // ip地址信息的数据结构 转化成网络字节序
if ( (h=gethostbyname(serverip))==0 )
{ close(m_sockfd); m_sockfd=0; return false; }
// 把服务器的地址和端口转换为数据结构
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);
// 向服务器发起连接请求
if (connect(m_sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))!=0)
{ close(m_sockfd); m_sockfd=0; return false; }
return true;
}
int CTcpClient::Send(const void *buf,const int buflen)
{
return send(m_sockfd,buf,buflen,0);
}
int CTcpClient::Recv(void *buf,const int buflen)
{
return recv(m_sockfd,buf,buflen,0);
}
多进程和单进程的区别在于服务端的处理,多进程可以同时接受很多个客户端的连接并通信。
这里使用类来封装socket,他的作用是
1)把数据初始化的代码放在构造函数中;
2)把关闭socket等释放资源的代码放在析构函数中;
3)把socket定义为类的成员变量,类外部的代码根本看不到socket。
4)代码更简洁,更安全(析构函数自动调用关闭socket,释放资源)。