(本节笔记的实验代码,在这里)
采用轮询方式接收来自客户端的连接请求,服务器端只能按顺序处理数个客户端的连接请求,也就是只能处理完A客户端的连接和数据收发后,才能按顺序继续处理B和C的客户端的请求。
2. 改善方法
服务器端采用多进程或多线程的方式,来同时并发处理来自多个客户端的连接请求。(若是TCP采用多进程方式)处理方法是,在父进程建立连接,而子进程负责进行数据的收发以及关闭客户端的连接的工作。
3. 综合实例
/* touch tcp_client_pthread.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#define PORTNUM 3333
int main(int argc, char **argv)
{
if(argc != 3)
{
printf("Usage: %s serverIP serverPort", argv[0]);
exit(1);
}
int sockfd;
char server_addr_a[4];
long addr_len;
char buffer[128];
struct sockaddr_in server_addr;
/* 1.创建socket */
if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
{
printf("Create socket fail!\n");
exit(1);
}
/* 2.建立连接 */
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
if(-1 == (connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr))))
{
printf("Create connect fail!\n");
exit(1);
}
else
printf("Create connect with %s successful!\n", argv[1]);
while(1)
{
/* 3.发送数据 */
printf("Please input something, input \"quit\" for close the client, \"end\" for exit for server:\n");
fgets(buffer, 128, stdin);
if(-1 == send(sockfd, buffer, strlen(buffer), 0))
{
printf("Send message fail!\n");
exit(1);
}
else
printf("The message had been sended!\n");
if(0 == strncmp(buffer, "quit", 4))
{
printf("Client will be close!\n");
break;
}
if(0 == strncmp(buffer, "end", 3))
{
printf("Server and Client will be close!\n");
break;
}
}
/* 4.结束app连接 */
close(sockfd);
return 0;
}
/* touch tcp_server_pthread.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#define PORTNUM 3333
#define BUFF_SZ 128
struct arg
{
int con_fd;
struct sockaddr_in con_addr;
};
void * thread_fun(void *arg)
{
struct arg arg_thread;
arg_thread.con_fd = ((struct arg *)arg)->con_fd;
arg_thread.con_addr = ((struct arg *)arg)->con_addr;
/* 5.接收数据 */
char buff[BUFF_SZ];
bzero(buff, sizeof(buff));
int recv_sz = 0;
while(1)
{
recv_sz = recv(arg_thread.con_fd, buff, BUFF_SZ, 0);
if(0 != recv_sz)
{
buff[recv_sz] = '\0';
printf("Server has received the message from : %s\n", inet_ntoa(arg_thread.con_addr.sin_addr.s_addr));
printf("The message is : %s\n", buff);
recv_sz = 0;
if(0 == strncmp(buff, "quit", 4))
{
printf("Client with %s will be close!\n", inet_ntoa(arg_thread.con_addr.sin_addr.s_addr));
/* 6.结束app连接 */
close(arg_thread.con_fd);
pthread_exit(NULL);
}
if(0 == strncmp(buff, "end", 3))
{
printf("Server and Client will be close!\n");
/* 6.结束app连接 */
close(arg_thread.con_fd);
exit(0);
}
}
}
}
int main()
{
int sockfd;
int acc_fd;
pthread_t thread_id;
long addr_len;
// char client_addr_a[10];
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
/* 1.创建socket */
if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
{
printf("Create socket fail!\n");
exit(1);
}
/* 2.绑定地址 */
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORTNUM);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr));
/* 3.监听连接 */
listen(sockfd, 5);
while(1)
{
/* 4.等待连接 */
addr_len = sizeof(struct sockaddr);
if(-1 == (acc_fd = accept(sockfd,(struct sockaddr*)(&client_addr), (socklen_t *)(&addr_len))))
{
printf("Create server connect fail!\n");
exit(1);
}
printf("The server has connect with %s\n", inet_ntoa(client_addr.sin_addr.s_addr));
struct arg arg_thread;
arg_thread.con_fd = acc_fd;
memcpy(&(arg_thread.con_addr), &client_addr, sizeof(struct sockaddr_in));
if(-1 == pthread_create(&thread_id, NULL, thread_fun, (void *)&arg_thread))
{
printf("Create pthread fail!\n");
exit(1);
}
}
}