本文是多进程编程,多线程请看(https://blog.csdn.net/xinger_28/article/details/94310088),在多线程编程一节详细介绍了网络套接字的编程流程。
//tcpsocket.h文件
#include<stdio.h>
#include<stdlib.h>
#include<error.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
int Socket();
int Bind(int sockfd,const char*ip,uint16_t port);
int Listen(int sockfd);
int Connect(int sockfd,const char * ip,uint16_t port);
int Accept(int sockfd,char**ip,uint16_t*port);
int Recv(int newfd,char*buf,size_t len);
int Send(int newfd,char*buf,size_t len);
int Close(int fd);
//tcpsocket.c文件
#include"tcpsocket.h"
int Socket()
{
int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
return sockfd;
}
int Bind(int sockfd,const char*ip,uint16_t port)
{
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr(ip);
int len=sizeof(struct sockaddr_in);
int ret=bind(sockfd,(struct sockaddr*)&addr,len);
return ret;
}
int Listen(int sockfd)
{
int ret=listen(sockfd,10);
return ret;
}
int Connect(int sockfd,const char* ip,uint16_t port)
{
struct sockaddr_in addr;
socklen_t len=sizeof(struct sockaddr_in);
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr(ip);
int ret=connect(sockfd,(struct sockaddr*)&addr,len);
if(ret<0)
{printf("connect error\n\n"); return -1;}
printf("%d\n",ret);
return ret;
}
int Accept(int sockfd,char**ip,uint16_t * port)
{
struct sockaddr_in clic ;
int len=sizeof(struct sockaddr_in);
int newfd=accept(sockfd,(struct sockaddr*)&clic,&len);
if(newfd<0)
{
return newfd;}
*ip=inet_ntoa(clic.sin_addr);
*port=ntohs(clic.sin_port);
return newfd;
}
int Recv(int newfd,char*buf,size_t len)
{
int ret=recv(newfd,buf,len,0);
if(ret<0)
printf("recv error\n");
else if (ret==0)
printf("connection shoutdown\n");
return ret;
}
int Send(int newfd,char * buf,size_t len)
{
int ret=send(newfd,buf,len,0);
if(ret<0)
printf("send error\n");
else if (ret==0)
printf("connection shoutdown\n");
return ret;
}
int Close(int fd)
{
close(fd);
}
//thread_service.c文件
//服务端代码
#include"tcpsocket.h"
#include"tcpsocket.h"
//检查返回值是否正常
int cheakRet(char*info,int ret)
{
if(ret<0)
{printf("%s\n",info);return -1;}
return ret;
}
//针对某一客户端进行收发数据
int Recv_Send(int fd,char*clicip,uint16_t clicport)
{
while(1){
char buf[1024]={0};
int ret=Recv(fd,buf,1023);
printf("connect : ip: %s port: %d\n",clicip,clicport);
printf("* clic say: %s \n",buf);
if(ret<0)
{printf("recv error\n");return -1;}
else if(ret==0)
{printf("connect is error\n");
return ret;}
memset(buf,0x00,1024);
printf("* send to :");
scanf("%s",buf);
printf("\n");
ret=Send(fd,buf,strlen(buf));
}
return 0;
}
//创建孙子进程进行收发数据
void Accept_(int sockfd,char*clicip,uint16_t clicport)
{
pid_t ret=fork();
if(ret==0)
{
pid_t gh=fork();
if(gh==0)
Recv_Send(sockfd,clicip,clicport);
exit(0);
}
else if(ret>0)
{close(sockfd);
wait(ret);
}
else
{printf("fork() error\n");
}
}
int main()
{
int sockfd=Socket();
cheakRet("Socket error",sockfd);
int ret=Bind(sockfd,"192.168.136.132",10000);
cheakRet("Bind error",ret);
ret=Listen(sockfd);
cheakRet("Listen error",ret);
while(1)
{
struct sockaddr_in clicaddr;
socklen_t len=sizeof(struct sockaddr_in);
char*clicip;
uint16_t clicport;
int newfd=Accept(sockfd,&clicip,&clicport);
printf("connect : ip: %s port: %d\n",clicip,clicport);
Accept_(newfd,clicip,clicport);
}
Close(sockfd);
return 0;
}
//clic.c文件
//用于客户端连接请求
#include"tcpsocket.h"
int main()
{
int sockfd=Socket();
if(sockfd<0)
{printf("sockfd error\n"); return -1;}
int ret;
//注意此处不需要为套接字绑定地址信息,因为这份代码是客户端的
//如果绑定了地址信息,那么只能启动一个客户机,其他客户端在启动时,将会绑定失败,因为一个端口只能被一个进程绑定
//因此不需要绑定地址信息,操作系统将会根据此时的网络状况,计算机此时的网络帮我们绑定合适的地址
int newfd=Connect(sockfd,"192.168.136.132",10000);
if(newfd<0)
{printf("connection error\n");return -1;}
while(1){
char buf[1024]={0};
printf("send to : ");
scanf("%s",buf);
ret=Send(sockfd,buf,strlen(buf));
if(ret<0)
{printf("recv error\n");return -1;}
else if(ret==0)
{printf("connect ir error\n");return -1;}
memset(buf ,0x00,1024);
ret=Recv(sockfd,buf,1023);
printf("service say:[%s]\n",buf);
if(ret<0)
{printf("Recv error\n");return -1;}
else if(ret==0)
{printf("quit\n");return -1;}
}
Close(sockfd);
return 0;
}
实际操作截图:
1.进行编译:
gcc threads_service.c tcpsocket.c -o pthread_servi
gcc clic.c tcpsocket.c -o clicl
2.运行结果:(先启动服务端进行监听)
服务端 客户端1 客户端2