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

来源:互联网 发布:学统计跟大数据 编辑:程序博客网 时间:2024/05/17 00:11

关于套接字编程
套接字编程
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 0
原创粉丝点击