服务器增强版(TCP)

1) 服务器端存在的问题:
*recv会阻塞
解决方法:1、多线程技术
2、 超时返回

2)如何用accept获取客户端IP和端口号
3)TCP通信应用场景:注册统计信息、智能聊天、云计算
4)补充知识
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。
  下面是几个字节顺序转换函数:
htonl():把32位值从主机字节序转换成网络字节序
htons():把16位值从主机字节序转换成网络字节序
ntohl():把32位值从网络字节序转换成主机字节序
ntohs():把16位值从网络字节序转换成主机字节序

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

void* rcv_data(void* arg);
void save_files(const char* str);
pthread_mutex_t m;
int main()
{ 
    pthread_mutex_init(&m,NULL);
//创建套接字     
    int socket_listen=socket(AF_INET,SOCK_STREAM,0);

    int opt_val=1;
    setsockopt(socket_listen,SOL_SOCKET,SO_REUSEADDR,&opt_val,sizeof(opt_val));
                                                     //设置文件 
//绑定地址
    struct sockaddr_in myaddr;
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr=INADDR_ANY;
    myaddr.sin_port=htons(6666);

    if(-1==bind(socket_listen,(struct sockaddr*)&myaddr,sizeof(myaddr)))
    {                          
        perror("bind");
        exit(-1);
    }
//将套接字设置为监听状态
    listen(socket_listen,5);

    struct timeval rcv_timeout;//设置超时为100ms
    rcv_timeout.tv_sec=0;
    rcv_timeout.tv_usec=100000;

    int sock_conn;
    struct sockaddr_in client_addr;
    socklen_t len;

    while(1)//一直监听
    {
//接受客户端连接请求
        len=sizeof(client_addr);

        sock_conn=accept(socket_listen,(struct sockaddr*)&client_addr,&len);
        setsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,&rcv_timeout,sizeof(rcv_timeout));//设置超时时间
        printf("%s:%d已近连接!\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        if(sock_conn==-1)
        {
            perror("accept");
            continue;
        }
        pthread_t tid;
        if(0!=pthread_create(&tid,NULL,rcv_data,(void*)sock_conn))
        {   
            perror("pthread_create");
            close(sock_conn);
        }
    }

//7、关闭监听套接字
    close(socket_listen);
    pthread_mutex_destroy(&m);
    return 0;

}
void* rcv_data(void* arg)
{
    pthread_detach(pthread_self());
    int sock_conn=(int)arg;
    //收发数据

    char msg[100];
    int ret;

    ret=recv(sock_conn,msg,sizeof(msg),0);//0表默认,不加额外控制
                                        //阻塞到收到消息,或连接断开 
    if(ret>0)
    {
        msg[ret]='\0';
        printf("客户端说:%s\n",msg);
        save_files(msg);
    }
    else if(ret==0)
    {
        printf("接收失败,连接断开\n");
    }
    else
    {
        if(errno==EAGAIN || errno==EWOULDBLOCK)
        {
            printf("接收超时!\n");
        }
        else
        {
            printf("其他错误\n");
        }
    }

    strcpy(msg,"收到您的信息");          
    ret=send(sock_conn,msg,strlen(msg),0);
//6、断开连接,即关闭连接套接字
    close(sock_conn);
    return NULL;
}
void save_files(const char* str)
{
    pthread_mutex_lock(&m);//保证下面三句话不被打断
    FILE* fp=fopen("name.txt","a");
    fprintf(fp,"%s\n",str);
    fclose(fp);
    pthread_mutex_unlock(&m);
}
//解决阻塞问题
//1.主线程接电话,然后分配给其他线程receive
//2.超时返回

//端口复用
//显示对方IP
//当客户端send,而服务器端关闭了连接套接字时,服务器进程会收到13号信号,导致进程结束,为了避免这种情况,要用信号处理函数对信号处理。

//应用:注册统计信息
//群聊天室
//云计算
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章