TCP\IP协议我之后会放在一起进行解释,因为这块较UDP来说比较复杂,我需要分成两三篇博客来分几个部分详谈,如TCP中的三次握手,四次挥手,超时重传等,IP协议的底层通信,路由,MAC帧等,都会讲到,我尽量总结点详细一点,以免遗漏。这里我就只放上TCP套接字编程的代码,接口和一些注意的点在之前的TCP/UDP套接字原理中都有讲到,看不懂的请戳这里->链接
大家研究代码的时候也可以与UDP对比着看,链接在这里->UDP原理及套接字编程实现
多线程/多进程版就是为了可以一次性处理多个客户端请求,两者之间也要对比着看:
- 多进程版
优点
- 处理多用户请求
- 稳定性比较强(进程的独立性)
缺点
- 创建子进程消耗时间,因为是建立连接后才创建
- 多进程服务器每个进程都吃资源,所以多进程服务器服务的客户是有上限的,而且这个上限较低
- CPU进行进程切换的周期边长,调度压力变大,会影响性能
- 多线程版
优点
- 同样可以处理多用户请求
- 较多进程:创建新线程时消耗时间较短,吃资源较少,切换成本小
缺点
- 稳定性较差,可能因为单线程安全问题导致服务器挂掉
两个版本都只使用中小型应用。
我就直接放代码了,有什么不对的点大家记得帮我指出来。
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#define MAX 128
typedef struct Arg{
int fd;
struct sockaddr_in addr;
}Arg;
void* Server(void *arg)
{
Arg* p = (Arg*)arg;
char buf[MAX];
while(1)
{
buf[0] = 0;
ssize_t s = read(p->fd,buf,sizeof(buf));
if(s < 0)
{
perror("read");
continue;
}else if(s == 0)
{
printf("client[%s] quit!\n",inet_ntoa(p->addr.sin_addr));
close(p->fd);
break;
}
buf[s] = 0;
printf("client[%s] says:%s\n",inet_ntoa(p->addr.sin_addr),buf);
write(p->fd,buf,strlen(buf));
}
return NULL;
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: [ip] [port]\n");
exit(1);
}
int sock = socket(AF_INET,SOCK_STREAM,0);//socket处于创建状态
if(sock < 0)
{
perror("socket");
exit(2);
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(sock,(const struct sockaddr*)&server,sizeof(server)) < 0)
{
perror("bind");
exit(3);
}
listen(sock,5);
if(sock < 0)//此时处于监听状态
{
perror("listen");
exit(4);
}
printf("Bind and listen successed ,waiting for accepting...\n");
for(;;)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int client_socket = accept(sock,(struct sockaddr*)&client,&len);
printf("。。。\n");
if(client_socket < 0)
{
continue;
}
pthread_t thread;
Arg* arg;
arg = (Arg*)malloc(sizeof(arg));
arg->fd = client_socket;
arg->addr = client;
if(pthread_create(&thread,NULL,Server,(void*)arg) == 0)
{
perror("pthread_create");
}
pthread_detach(thread);//线程分离
// pid_t son = fork();注释注掉的部分是多进程版本
// if(son < 0)
// {
// perror("fork");
// return 0;
// }
// if(son == 0)
// {
// pid_t son_son = fork();
// if(son_son == 0)
// {
// Server(client_socket,&client);
// }
// exit(0);
// }
// wait(NULL);
}
return 0;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX 128
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: [ip] [port]\n");
exit(1);
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(2);
}
struct sockaddr_in client;
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(argv[1]);
client.sin_port = htons(atoi(argv[2]));
socklen_t len = sizeof(client);
if(connect(sock,(struct sockaddr*)&client,len) < 0)
{
perror("connect");
exit(3);
}
char buf[MAX];
printf("connect success....\n");
while(1)
{
printf("Client say#");
buf[0] = 0;
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf));
if(s > 0)
{
buf[s-1] = 0;
write(sock,buf,strlen(buf));
if(strcmp("quit",buf) == 0)
{
printf("connect quit...\n");
close(sock);
return 0;
}
read(sock,buf,sizeof(buf));
fflush(stdout);
printf("Server reply#%s \n",buf);
}
}
close(sock);
return 0;
}