单进程 多任务 c语言,linux下 socket tcp Server c语言编写(分别实现单进程,多进程,多线程)...

TCP 迭代服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。TCP 迭代服务器一次只能处理一个客户端的请求,只有在这个客户的所有请求满足后,服务器才可以继续后面的请求。如果有一个客户端占住服务器不放时,其它的客户机都不能工作了,因此,TCP 服务器一般很少用迭代服务器模型的。

tcp服务器端框架

1.创建tcp套接字

2. 绑定套接字

3. 监听套接字

4. 调用accept()阻塞等待

5. 处理客户端的请求

6. 关闭连接套接字

7. 关闭监听套接字

tcp客户端框架

1.创建tcp套接字

2.调用connect()连接服务器

3.处理服务器端返回的信息

由于客户端不需要固定的端⼜号,因此不必调⽤bind(),客户端的端⼜号由内核⾃动分配。注意, 客户端不是不允许调⽤bind(),只是没有必要调⽤bind()固定⼀个端⼜号,服务器也不是必须调⽤bind(),但如果服务器不调⽤bind(),内核会⾃动给服务器分配监听端⼜,每次启动服务器时端⼜ 号都不⼀样,客户端要连接服务器就会遇到⿇烦。

单进程

server.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define _PORT_ 9999

#define _BACKLOG_ 10

int main()

{

int sock=socket(AF_INET,SOCK_STREAM,0);

if(sock<0)

{

printf("socket()\n");

}

struct sockaddr_in server_socket;

struct sockaddr_in socket;

bzero(&server_socket,sizeof(server_socket));

server_socket.sin_family=AF_INET;

server_socket.sin_addr.s_addr=htonl(INADDR_ANY);

server_socket.sin_port=htons(_PORT_);

if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0)

{

printf("bind()\n");

close(sock);

return 1;

}

if(listen(sock,_BACKLOG_)<0)

{

printf("listen()\n");

close(sock);

return 2;

}

printf("success\n");

for(;;)

{

socklen_t len=0;

int client_sock=accept(sock,(struct sockaddr*)&socket,&len);

if(client_sock<0)

{

printf("accept()\n");

return 3;

}

char buf_ip[INET_ADDRSTRLEN];

memset(buf_ip,'\0',sizeof(buf_ip));

inet_ntop(AF_INET,&socket.sin_addr,buf_ip,sizeof(buf_ip));

printf("get connect\n");

while(1)

{

char buf[1024];

memset(buf,'\0',sizeof(buf));

read(client_sock,buf,sizeof(buf));

printf("client:# %s\n",buf);

printf("server:$ ");

memset(buf,'\0',sizeof(buf));

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1]='\0';

if(strncasecmp(buf,"quit",4)==0)

{

printf("quit\n");

break;

}

write(client_sock,buf,strlen(buf)+1);

printf("wait...\n");

}

close(client_sock);

}

close(sock);

return 0;

}

多进程

怎么将单进程的代码改为多进程的代码呢?

调用fork()函数,创建子进程,将所有的客户端的请求处理的内容都放在子进程中处理。

在 Linux 环境下多进程的应用很多,其中最主要的就是网络/客户服务器。多进程服务器是当客户有请求时,服务器用一个子进程来处理客户请求。父进程继续等待其它客户的请求。这种方法的优点是当客户有请求时,服务器能及时处理客户,特别是在客户服务器交互系统中。对于一个 TCP 服务器,客户与服务器的连接可能并不马上关闭,可能会等到客户提交某些数据后再关闭,这段时间服务器端的进程会阻塞,所以这时操作系统可能调度其它客户服务进程,这比起循环服务器大大提高了服务性能。

server.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define _PORT_ 9999

#define _BACKLOG_ 10

int main()

{

int sock=socket(AF_INET,SOCK_STREAM,0);

if(sock<0)

{

printf("socket()\n");

}

struct sockaddr_in server_socket;

struct sockaddr_in socket;

bzero(&server_socket,sizeof(server_socket));

server_socket.sin_family=AF_INET;

server_socket.sin_addr.s_addr=htonl(INADDR_ANY);

server_socket.sin_port=htons(_PORT_);

if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0)

{

printf("bind()\n");

close(sock);

return 1;

}

if(listen(sock,_BACKLOG_)<0)

{

printf("listen()\n");

close(sock);

return 2;

}

printf("success\n");

for(;;)

{

socklen_t len=0;

int client_sock=accept(sock,(struct sockaddr*)&socket,&len);

if(client_sock<0)

{

printf("accept()\n");

return 3;

}

char buf_ip[INET_ADDRSTRLEN];

memset(buf_ip,'\0',sizeof(buf_ip));

inet_ntop(AF_INET,&socket.sin_addr,buf_ip,sizeof(buf_ip));

printf("get connect\n");

pid_t fd=fork();

if(fd<0)

printf("fork()\n");

if(fd==0)

{

close(sock);//关闭监听套接字

printf("port=%d,ip=%s\n",ntohs(socket.sin_port),buf_ip);

while(1)

{

char buf[1024];

memset(buf,'\0',sizeof(buf));

read(client_sock,buf,sizeof(buf));

printf("client:# %s\n",buf);

printf("server:$ ");

memset(buf,'\0',sizeof(buf));

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1]='\0';

if(strncasecmp(buf,"quit",4)==0)

{

printf("quit\n");

break;

}

write(client_sock,buf,strlen(buf)+1);

printf("wait...\n");

}

close(fd);

}

else if(fd>0)

{

close(fd);

}

}

close(sock);

return 0;

}

多线程

多线程和多进程的处理方式类似,都是创建一个新的线程,客户端有请求时,用新创建的线程处理。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define _PORT_ 9999

#define _BACKLOG_ 10

void *fun(void* arg)

{

int client_sock = (int)arg;

while(1)

{

char buf[1024];

memset(buf,'\0',sizeof(buf));

read(client_sock,buf,sizeof(buf));

printf("client:# %s\n",buf);

printf("server:$ ");

memset(buf,'\0',sizeof(buf));

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1]='\0';

if(strncasecmp(buf,"quit",4)==0)

{

printf("quit\n");

break;

}

write(client_sock,buf,strlen(buf)+1);

printf("wait...\n");

}

close(client_sock);

}

int main()

{

int sock=socket(AF_INET,SOCK_STREAM,0);

if(sock<0)

{

printf("socket()\n");

}

struct sockaddr_in server_socket;

struct sockaddr_in socket;

pthread_t thread_id;

bzero(&server_socket,sizeof(server_socket));

server_socket.sin_family=AF_INET;

server_socket.sin_addr.s_addr=htonl(INADDR_ANY);

server_socket.sin_port=htons(_PORT_);

if(bind(sock,(struct sockaddr*)&server_socket,sizeof(struct sockaddr_in))<0)

{

printf("bind()\n");

close(sock);

return 1;

}

if(listen(sock,_BACKLOG_)<0)

{

printf("listen()\n");

close(sock);

return 2;

}

printf("success\n");

for(;;)

{

socklen_t len=0;

int client_sock=accept(sock,(struct sockaddr*)&socket,&len);

if(client_sock<0)

{

printf("accept()\n");

return 3;

}

char buf_ip[INET_ADDRSTRLEN];

memset(buf_ip,'\0',sizeof(buf_ip));

inet_ntop(AF_INET,&socket.sin_add,buf_ip,sizeof(buf_ip));

printf("get connect,ip is%s\n",buf_ip);

printf("port=%d\n",ntohs(socket.sin_port));

pthread_create(&thread_id, NULL, (void *)fun, (void *)client_sock);

pthread_detach(thread_id);

}

close(sock);

return 0;

}

不管是哪一种的服务器,客户端都是一样的

client.c

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVER_PORT 9999

int main(int argc,char* argv[])

{

if(argc!=2)

{

printf("Usage:client IP\n");

return 1;

}

char *str=argv[1];

char buf[1024];

memset(buf,'\0',sizeof(buf));

struct sockaddr_in server_sock;

int sock = socket(AF_INET,SOCK_STREAM,0);

bzero(&server_sock,sizeof(server_sock));

server_sock.sin_family=AF_INET;

inet_pton(AF_INET,str,&server_sock.sin_addr);

server_sock.sin_port=htons(SERVER_PORT);

int ret=connect(sock,(struct sockaddr *)&server_sock,sizeof(server_sock));

if(ret<0)

{

printf("connect()\n");

return 1;

}

printf("connect success\n");

while(1)

{

printf("client:# ");

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1]='\0';

write(sock,buf,sizeof(buf));

if(strncasecmp(buf,"quit",4)==0)

{

printf("quit\n");

break;

}

printf("wait..\n");

read(sock,buf,sizeof(buf));

printf("server:$ %s\n",buf);

}

close(sock);

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值