如果需要一个服务端可以连接多个客户端,并同时与多个(不超多listen第二个参数及最大同时并发数)客户端通信,可以利用多进程即创建子进程,子进程来完成服务端的接受和发送数据;也可以创建多个线程。对于tcp一些接口具体使用可以查看这篇博客:https://blog.csdn.net/sophia__yu/article/details/82827500
tcp客户端代码
//tcp 客户端代码
//1.创建套接字
//2.绑定地址信息
//3.向服务端发送连接请求
//4.发送数据
//5.接受数据
//6.关闭socket描述符
#include<stdio.h>
#include<error.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage ip and port\n");
}
//1.创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sockfd<0)
{
perror("socket error");
return -1;
}
//2.绑定地址信息(不推荐手动写绑定信息代码)
//3.向服务端发送连接请求
//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
struct sockaddr_in ser_addr;
ser_addr.sin_family=AF_INET;
ser_addr.sin_port=(htons)(atoi(argv[2]));
ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);//因为argv[]是char*,用atoi使字符串转成整型
int len=sizeof(struct sockaddr_in);
int ret=connect(sockfd,(struct sockaddr*)&ser_addr,len);
if(ret<0)
{
perror("connect error");
close(sockfd);
return -1;
}
//连接成功,socket描述符里有服务端和客户端IP地址和port
while(1)
{
//4.发送数据
// ssize_t send(int sockfd, const void *buf, size_t len, int flags);
char buff[1024]={0};
printf("please send\n");
scanf("%s",buff);
ret=send(sockfd,buff,strlen(buff),0); //默认阻塞接受数据
if(ret<0)
{
perror("send error");
close(sockfd);
return -1;
}
//5.接受数据
//ssize_t recv(int sockfd, void *buf, size_t len, int flags);
memset(buff,0x00,1024);
ret=recv(sockfd,buff,1023,0);//默认阻塞接受数据
if(len<0)//小于0接受失败
{
perror("recv error");
close(sockfd);
continue;
}
else if(len==0)//等于0对端将连接断开
{
perror("peer has performed an orderly shutdown");
close(sockfd);
continue;
}
printf("[%s:%d]say:%s\n",(inet_ntoa)(ser_addr.sin_addr),(ntohs)(ser_addr.sin_port),buff);
}
close(sockfd);
return 0;
}
多进程服务端代码:
//多进程的tcp服务端代码
#include<stdio.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<wait.h>
#include<stdlib.h>
#include<arpa/inet.h>
void profunc(int sockfd)
{
int pid=fork();
if(pid<0)
{
perror("fork error");
close(sockfd);
return ;
}
else if(pid==0){
//子进程 接受数据和发送数据
while(1){
char buff[1024]={0};
int len=recv(sockfd,buff,1023,0);//阻塞接受数据
if(len<0)
{
perror("recv error");
close(sockfd);
return ;
}
else if(len==0)
{
perror("peer shutdown");
close(sockfd);
return ;
}
printf("ser say:%s\n",buff);
send(sockfd,"hello",5,0);//服务端默认发送hello
}
close(sockfd);
}
else
{
//父进程
close(sockfd);//子进程和父进程的sockfd在不同空间,所以如果父进程不对sockfd做什么,需要关闭,但是父进程最好不对sochfd不做什么,否则无法区别发送或接
受数据是父进程还是子进程
}
}
void sigcb(int signum)
{
while(waitpid(-1,NULL,WNOHANG)!=0)//没有子进程退出将返回0,用循环是将等待子进程资源回收完毕
{
}
}
int main(int argc,char* argv[])
{
signal(SIGCHLD,sigcb);//将SIGCHLD自定义设置为等待子进程退出功能
if(argc!=3)
{
printf("Usage:./ ip port\n");
}
//1.创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6
if(sockfd<0)
{
perror("socket error");
return -1;
}
//2.绑定地址信息
struct sockaddr_in ser_addr;
ser_addr.sin_family=AF_INET;
ser_addr.sin_port=htons((atoi)(argv[2]));
ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);
int len=sizeof(struct sockaddr_in);
int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len);
if(ret<0)
{
perror("bind error");
close(sockfd);
return -1;
}
//3.监听,listen只是设置好socket的属性,连接成功队列最多有5个结点
if(listen(sockfd,5)<0)
{
perror("losten error");
close(sockfd);
return -1;
}
//4.获取新连接的客户端信息
//多进程,创建子进程,子进程来接受发送数据,从而实现一个服务端可以同时连接多个客户端
while(1)
{
struct sockaddr_in cli_addr;
len=sizeof(struct sockaddr_in);
int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);
profunc(newsockfd);
}
close(sockfd);
return 0;
}
第一个客户端:
第二个客户端:
服务端:
多线程tcp服务端代码
//多线程的tcp服务端代码
#include<stdio.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<wait.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<pthread.h>
void* the_start(void* arg)
{
int sockfd=(int)arg;
while(1)
{
//接受数据
char buff[1024]={0};
int len=recv(sockfd,buff,1023,0);//阻塞接受数据
if(len<0)
{
perror("recv error");
close(sockfd);
return ;
}
else if(len==0)
{
perror("peer shutdown");
close(sockfd);
return ;
}
printf("ser say:%s\n",buff);
send(sockfd,"hello",5,0);//服务端默认发送hello
}
close(sockfd);
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage:./ ip port\n");
}
//1.创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6
if(sockfd<0)
{
perror("socket error");
return -1;
}
//2.绑定地址信息
struct sockaddr_in ser_addr;
ser_addr.sin_family=AF_INET;
ser_addr.sin_port=htons((atoi)(argv[2]));
ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);
int len=sizeof(struct sockaddr_in);
int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len);
if(ret<0)
{
perror("bind error");
close(sockfd);
return -1;
}
//3.监听,listen只是设置好socket的属性,连接成功队列最多有5个结点
if(listen(sockfd,5)<0)
{
perror("losten error");
close(sockfd);
return -1;
}
//4.获取新连接的客户端信息
//创建多个线程
while(1)
{
struct sockaddr_in cli_addr;
len=sizeof(struct sockaddr_in);
int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);
//创建线程
// // int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
pthread_t tid;
int ret;
ret=pthread_create(&tid,NULL,the_start,(void*)newsockfd);
}
close(sockfd);
return 0;
}
第一个客户端:
第二个客户端:
服务端: