TCP_Server

一,socket编程

在TCP/IP协议中,IP地址+TCP/UDP的端口号,唯一地标识了网络通讯中的一个进程,“IP地址+端口号”就称为socket。

二,TCP_Server

2.1 基于多线程

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>

static void userHelp(const char* str)
{
 printf("%s [local_ip] [local_port]",str);
}

int startup(const char* _ip,int _port)
{
  //socket打开一个 网络通讯端口,其中AF_INET:表示IPV4,SOCK_STREAM:表示面向流的传输, 
  //protocol参数默认选择为0 
 int sock=socket(AF_INET,SOCK_STREAM,0);
 if(sock==-1)
 {
  perror("socket()");
  exit(-1);
 }
 struct sockaddr_in local;
 local.sin_family=AF_INET;
 local.sin_port=htons(_port);
 local.sin_addr.s_addr=inet_addr(_ip);
//bind的作用是将参数sock与local绑定在一起 
 //使sock这个文件描述符监听local所描述的地址与端口号 
 //成功返回0,失败返回-1 
 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) //success zero is return
   {
    perror("bind()");
    exit(-2);

   }
//listen声明sock处于监听状态,并且最多允许5个客户端处于连接等待状态  
//如果收到更多的请求便忽略 
if(listen(sock,5)==-1)  //add listener
{
 perror("listen()");
 exit(-3);
}
  return sock;
}

void* handlerRequest(void *arg)
{
 int new_fd=(int)arg;
 printf("new_fd=%d\n",new_fd);
 while(1)
 {
  char buffer[1024];
 ssize_t s=read(new_fd,buffer,sizeof(buffer));
  if(s==-1)
     {
      perror("read");

     } 
  if(s>0)
  {
   buffer[s]='\0';
   printf("client:%s\n",buffer);
   write(new_fd,buffer,strlen(buffer));
  }
  else
  {
   printf("read done...break\n");
   break;
  }

 }
}
 int main(int argc,char* argv[])
{
if(argc!=3)
 {
  userHelp(argv[0]);
  return 1;
 }
int listen_sock=startup(argv[1],atoi(argv[2]));
while(1)
{
 struct sockaddr_in client;
 socklen_t len=sizeof(client);
 //accept阻塞式等待,用来接收连接 
 int new_fd=accept(listen_sock,(struct sockaddr*)&client,&len);
 if(new_fd<0)
 {
  perror("accept()");
  continue;
 }
 printf("get a new client,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
 pthread_t id;
 pthread_create(&id,NULL,handlerRequest,(void*)new_fd);
 pthread_detach(id);
//return 0;
}
return 0;
}

2.2 基于多进程

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>

static void userHelp(const char* str)
{
 printf("%s [local_ip] [local_port]",str);
}

int startup(const char* _ip,int _port)
{
 int sock=socket(AF_INET,SOCK_STREAM,0);
 if(sock==-1)
 {
  perror("socket()");
  exit(-1);
 }
 struct sockaddr_in local;
 local.sin_family=AF_INET;
 local.sin_port=htons(_port);
 local.sin_addr.s_addr=inet_addr(_ip);

 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) //success zero is return
   {
    perror("bind()");
    exit(-2);

   }
if(listen(sock,5)==-1)  //add listener
{
 perror("listen()");
 exit(-3);
}
  return sock;
}

 int main(int argc,char* argv[])
{
if(argc!=3)
 {
  userHelp(argv[0]);
  return 1;
 }
int listen_sock=startup(argv[1],atoi(argv[2]));
while(1)
{
 struct sockaddr_in client;
 socklen_t len=sizeof(client);
 int new_fd=accept(listen_sock,(struct sockaddr*)&client,&len);
 if(new_fd<0)
 {
  perror("accept()");
  continue;
 }

//建立进程 
pid_t id=fork();
if(id<0)
{
 perror("fork");
 close(new_fd);
}
else if(id==0) 
{       
  close(listen_sock);
  if(fork()>0)
  {
   close(new_fd);         
   exit(0);
  }
while(1)
{
 char buf[1024];
 ssize_t s=read(new_fd,buf,sizeof(buf)-1);
 if(s>0)
 {
 printf("get a new client,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));      
  buf[s]=0;
  printf("client:%s\n",buf);
  write(new_fd,buf,strlen(buf));
 }
 else
 {
 printf("read done...,break\n");
 break;
 }
}
close(new_fd);

}
}
return 0;
}

三,client

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
static void userHelp(char* str)
{
 printf("%s [server_ip] [server_port]",str);
}
int main(int argc,char * argv[])
{
 if(argc!=3)
 {
  userHelp(argv[0]);
  return 1;
 }

 int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
 perror("sock()");
 exit(-1);

}
struct sockaddr_in client;
client.sin_family=AF_INET;
client.sin_port=htons(atoi(argv[2]));
client.sin_addr.s_addr=inet_addr(argv[1]);

if(connect(sock,(struct sockaddr*)&client,sizeof(client))<0)
{
 perror("connect()");
 exit(-2);

}
while(1)
{
char buffer[1024];
printf("please input:");
fflush(stdout);
ssize_t s=read(0,buffer,sizeof(buffer)-1);
if(s>0)
{
 buffer[s-1]=0;
 write(sock,buffer,strlen(buffer));
 ssize_t _s=read(sock,buffer,sizeof(buffer)-1);
 if(_s>0)
 {
 buffer[_s]=0;
 printf("server echo#%s\n",buffer);
 }

}
}
return 0;
}

四,测试结果(基于多进程版本)

clent:

这里写图片描述

server:

这里写图片描述

五,server,bind()失败原因调研

在建立连接后,我们发现如果单方面的结束掉server端,再在相同的端口运行server端程序将会出现以下问题:

这里写图片描述
这是因为,虽然server的应用程序终止了,但TCP的连接并没有完全断开,因此不能再次监听同样的server端口;我们用“netstat”命令查看一下:
这里写图片描述

我们发现8080端口还在被占用,这是因为TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL的时间后才能回到closed状态,所以当我们在连接中用“ctrl+c”结束掉server后,还需要进行等待,所以端口还是会处于监听状态。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值