socket套接字编写多线程多进程的server和client

关于套接字编程
套接字编程
IP地址+端口号就成为套接字
在TCP协议中。建立两个连接的进程个字有一个socket来标识,那么这两个socket组成desocketpair就表示一个唯一链接
socket用来描述网络连接一对一关系
socket地址的数据类型及相关函数
这里写图片描述
第一个是通用接口
第二个表示IPV4的地址使用socketaddr_in
第三个表示预间套接字
这样我们只需要知道某种socket结构体的首地址,就可以根据地质的具体类型字段确定结构体中的内容
服务器需要进行的操作
1>、服务器首先获得sockect调用socket函数
在这里我们用的是IPV4因此类型选择AF_INET。
由于是16位地址类型的AF_INET的所以我们采用sockaddr_in 类型的
客户端和服务端是一样的
这里写图片描述
sa_family:表示地址所属的类型 在这道理我们是AF_INET
_be16代表16位端口号
为什么是16位,因为在这里我们是从上往下进行交付
TCP的报头是16位端口号
server.sin_port=htons(atoi(port));
htons的功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)
2>、接下来就应该绑定端口 调用bind函数绑定IP和端口号
3>、接下来服务器需要不断去监听有没有客户端发来请求调用listen函数
4>、接下来我们需要调用accept函数
accept()系统调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符。新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。
5>、之后就可以进行一系列的读写操作了

2、客户端进行的操作就比较简单,他只需要和服务器进行连接
version1版本的server和client

server.c
#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<stdlib.h>
int startup(char*ip,int port)
{
     int sock=socket(AF_INET,SOCK_STREAM,0);
     if(sock<0)
     {
          perror("socket");
          exit(2);
     }
    struct sockaddr_in server;
     server.sin_family=AF_INET;
     server.sin_port=htons(atoi(port));
     server.sin_addr.s_addr=inet_addr(ip);
    if(bind(sock,(struct sockaddr*)&server,sizeof(struct sockaddr_in))<0)
     {
          perror("bind");
          exit(3);
     }
    if(listen(sock,10)<0)
     {
          perror("listen");
          exit(4);
     }
     return sock;
}
void *usage(const char*proc)
{
   printf("%s [local_ip] [local_port]\n",proc);
   exit(5);
}
int main(int argv,char*argc[])
{
     if(argv!=3)
     {
          usage(argc[0]);
          exit(6);
     }
     int listen_sock=startup(argc[1],argc[2]);
     printf("fd:%d\n",listen_sock);
     while(1)
     {
          struct sockaddr_in client;
          socklen_t len=sizeof(client);
          int newsock=accept(listen_sock,(struct sockaddr*)&client,&len);
        if(newsock<0)
          {
               perror("accept");
               continue;
          }
          printf("get a client:[%s:%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
          char buf[1024];
          while(1)
          {
            ssize_t ret=read(newsock,buf,sizeof(buf)-1);
               if(ret>0)
               {
                    buf[ret]=0;
                   printf("client say:%s\n",buf);
                   write(newsock,buf,sizeof(buf)-1);
               }
               else if(ret==0)
               {
                    printf("client quit!\n");
                    break;
               }
               else
               {
                    perror("read");
                    exit(7);
               }
          } 
         close(newsock);
     }
     close(listen_sock);
     return 0;
}

client.c
#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<stdlib.h>
void Usage(char*proc)
{
   printf("%s [server_ip] [server_port]\n",proc);
   return 1;
}
int main(int argv,char*argc[])
{
     if(argv!=3)
     {
          Usage(argc[0]);
        return 2;
     }
     int sock=socket(AF_INET,SOCK_STREAM,0);
     struct sockaddr_in server_sock;
     server_sock.sin_family=AF_INET;
     server_sock.sin_port=htons(atoi(argc[2]));
     server_sock.sin_addr.s_addr=inet_addr(argc[1]);
     if(connect(sock,(struct sockaddr*)(&server_sock),sizeof(server_sock))<0)
     {
        perror("connect");
        return 3;
     }
   while(1)
  {
    printf("please Enter:\n");
    fflush(stdout);
     char buf[1024];
    ssize_t ret=read(0,buf,sizeof(buf)-1);
     if(ret>0)
     {
       buf[ret-1]=0;
       write(sock,buf,sizeof(buf)-1);
        read(sock,buf,sizeof(buf)-1);
        printf("server say:%s\n",buf);
     }
}
   close(sock);
   return 3;
}

多进程版本的:

**server.c**

#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<stdlib.h>
int startup(char*ip, int port)
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock<0)
    {
        perror("socket");
        exit(2);
    }
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(port));
    server.sin_addr.s_addr = inet_addr(ip);
    if (bind(sock, (struct sockaddr*)&server, sizeof(struct sockaddr_in))<0)
    {
        perror("bind");
        exit(3);
    }
    if (listen(sock, 10)<0)
    {
        perror("listen");
        exit(4);
    }
    return sock;
}
void *usage(const char*proc)
{
    printf("%s [local_ip] [local_port]\n", proc);
    exit(5);
}
int main(int argv, char*argc[])
{
        if(argv!=3)
        {
            Usage(argc[0]);
         }
    int listen_sock = startup(argc[1], argc[2]);
    printf("fd:%d\n", listen_sock);
    while (1)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int newsock = accept(listen_sock, (struct sockaddr*)&client, &len);
        if (newsock<0)
        {
            perror("accept");
            continue;
        }
        printf("get a client:[%s:%d]\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
        pid_t id = fork();
        if (id == 0)
        {
                        close(listen_sock);
            if (fork() == 0)
            {
                char buf[1024];
                while (1)
                {
                    ssize_t ret = read(newsock, buf, sizeof(buf)-1);
                    if (ret>0)
                    {
                        buf[ret] = 0;
                        printf("client say:%s\n", buf);
                        write(newsock, buf, sizeof(buf)-1);
                    }
                    else if (ret == 0)
                    {
                        printf("client quit!\n");
                        close(newsock);
                        exit(7);
                    }
                    else
                    {
                        perror("read");
                        exit(8);
                    }
                }
            }
            else
            {
                exit(9);
            }
        }
        else if (id>0)
        {
            close(newsock);
                        while((waitpid(-1,NULL,WNOHANG)>0));
                        continue;
        }
        else
        {
            perror("fork");
            exit(9);
        }
    }
    close(listen_sock);
    return 0;
}

多线程版本的:

#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<stdlib.h>
#include <pthread.h>
int startup(char*ip, int port)
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock<0)
    {
        perror("socket");
        exit(2);
    }
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(port));
    server.sin_addr.s_addr = inet_addr(ip);
    if (bind(sock, (struct sockaddr*)&server, sizeof(struct sockaddr_in))<0)
    {
        perror("bind");
        exit(3);
    }
    if (listen(sock, 10)<0)
    {
        perror("listen");
        exit(4);
    }
    return sock;
}
void *Usage(const char*proc)
{
    printf("%s [local_ip] [local_port]\n", proc);
    exit(5);
}
void* thread_handler(void*arg)
{
       int newsock=*((int*)arg);
            char buf[1024];
              while (1)
            {
             ssize_t ret = read(newsock, buf, sizeof(buf)-1);
             if (ret>0)
             {
                buf[ret] = 0;
                printf("client say:%s\n", buf);
                write(newsock, buf, sizeof(buf)-1);
             }
             else if (ret == 0)
             {
                printf("client quit!\n");
                close(newsock);
                exit(7);
             }
             else
             {
                perror("read");
                exit(8);
             }
       }
}


int main(int argv, char*argc[])
{
        if(argv!=3)
        {
            Usage(argc[0]);
         }
    int listen_sock = startup(argc[1], argc[2]);
    printf("fd:%d\n", listen_sock);
    while (1)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int newsock = accept(listen_sock, (struct sockaddr*)&client, &len);
        if (newsock<0)
        {
            perror("accept");
            continue;
        }
        printf("get a client:[%s:%d]\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
            pthread_t  tid;
            int ret=pthread_create(&tid,NULL,thread_handler,&newsock);
            if(ret<0)
             {
                perror("pthread_create");
                exit(9);
    }
        pthread_detach(tid);
}
    close(listen_sock);
    return 0;
 }

为什么会出现server bind失败
看下图:
由于我们的客户端还没有退出,服务器就先断开连接了造成了这种情况,为什么会出现这种现象呢?
这里写图片描述

这里写图片描述

通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT状态
TCP是全双工的通信,它是提供可靠传输的,它有着三次握手和四次挥手,在四次挥手的过程中,主动断开连接的一方会进入TIME_WAIT状态。如果服务器端先断开连接那么就会进入TIME_WAIT状态。为什么需要TIME_WAIT?TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制,是必要的逻辑保证。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值