tcp_bf_ser.c
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#define SERV_PORT 8888
#define SERV_IP_ADDR "192.168.11.128"
#define BACKLOG 5
#define BUFSIZE 1024
#define QUIT_STR "QUIT"
void * client_handler(void * arg);
int main()
{
int sockfd;
//1.创建套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket");
exit(1);
}
//2.给套接字绑定地址
struct sockaddr_in myaddr;
//清零myaddr结构体里的数据
bzero(&myaddr,sizeof(myaddr));
//初始化myaddr结构体
myaddr.sin_family=AF_INET; //协议簇
myaddr.sin_port=htons(SERV_PORT); //指定端口,主机字节序转换为网络字节序
myaddr.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);//指定IP地址,将字符串转为无符号整型
if(ret ==-1)
{
perror("bind");
exit(2);
}
//3.使套接字能够监听,能够被其他客服端连接
int res_lis=listen(sockfd,BACKLOG);
if(res_lis==-1)//表示系统允许11(2*5+1)个客户端同时进行三次握手
{
perror("listen");
exit(3);
}
int newfd;
pthread_t pid;
struct sockaddr_in saddr;
bzero(&saddr,sizeof(saddr));
//等待连接
socklen_t length = sizeof(saddr);
while(1)
{
//4.阻塞等待接受客服端连接
newfd=accept(sockfd,(struct sockaddr *)&saddr,&length);
char ipv4_addr[16];
if(inet_ntop(AF_INET,(void *)&saddr.sin_addr.s_addr,ipv4_addr,sizeof(saddr))==0)
{
perror("inet_ntop");
exit(1);
}
printf("client 地址是:%s,%d\n",ipv4_addr,ntohs(saddr.sin_port));
if(newfd<0)
{
perror("accept");
exit(5);
}
pthread_create(&pid,NULL,&client_handler,(void *)&newfd);
}
return 0;
}
void * client_handler(void * arg)
{
int newfd=*(int *)arg;
char buff[BUFSIZE];
int ret2;
printf("new pthread is %d\n",newfd);
while(1)
{
memset((void *)buff,0,1024);
ret2=read(newfd,buff,sizeof(buff));
if(ret2<=0)
{
break;
}
printf("receive data is %s\n",buff);
//判断是否接受到的数据是不是QUIT_STR,是的话,就退出此次循环
if(!strncasecmp(buff,QUIT_STR,strlen(QUIT_STR)))
{
printf("client is exiting\n");
break;
}
}
close(newfd);
}
tcp_cli.c
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#define SERV_PROT 8888
#define SERV_IP_ADDR "192.168.11.128"
#define BUFSZIE 1024
#define QUIT_STR "QUIT"
int main(int arc,char **arg)
{
if(arc != 3)
{
exit(1);
}
int port;
port=atoi(arg[2]);//将字符串转化为整形
int sockfd;
//1.创建一个套接字
sockfd=socket(AF_INET,SOCK_STREAM,0);
//2.不调bind函数来给套接字绑定地址,由系统自动分配
//3.连接服务器件
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(port);//atoi函数将字符串转化为整形
//saddr.sin_port=htons(SERV_PROT);
//saddr.sin_addr.s_addr=INADDR_ANY;
saddr.sin_addr.s_addr=inet_addr(arg[1]);
if(connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr)) == -1)
{
perror("connect");
exit(1);
}
char buffer[1024];
while(1)
{
memset(buffer,0,1024);
if(fgets(buffer,1024,stdin)==NULL)
{
continue;
}
send(sockfd,buffer,sizeof(buffer),0);
if(!strncasecmp(buffer,QUIT_STR,strlen(QUIT_STR)))
{
break;
}
}
close(sockfd);
return 0;
}
可以打开多个终端,其中一个终端来作为服务器,其他终端都作为客服端,服务能被多个客服端连接。
过程;服务器每接收到一个客户端连接,都会新创建一个子线程来接收刚连接的客服端发送过来的数据。
重点:accept和read都有阻塞的作用。