TCP-server编程

一、基本解释 

      在之前的博客中我已经简单的介绍过TCP建立连接时的三次握手,以及在断开连接时的四次挥手,在此我就不再多说了,此次介绍基于TCP的套接字编程。在此类编程中会用到一些结构体以及函数,下来我简单地介绍下这些:

1.struct sockaddr_in

其结构如下

sockaddr_in(在netinet/in.h中定义):

struct sockaddr_in

{

     short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/

     unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/

     struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/

     unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/

};

2.bind函数

int bind(int sockfd, struct sockaddr* addr,socklen_t  addrlen)

参数sockfd
指定地址与哪个套接字绑定,这是一个由之前的socket函数调用返回的套接字。调用bind的函数之后,该套接字与一个相应的地址关联,发送到这个地址的数据可以通过这个套接字来读取与使用。
参数addr
正如大多数socket接口一样,内核不关心地址结构,当它复制或传递地址给驱动的时候,它依据这个值来确定需要复制多少数据。这已经成为socket接口中最常见的参数之一了。
参数addrlen
是参数addr的大小

3.listen函数

int listen(int sock, int backlog);

sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。

所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

4.accept函数

int accept(int sock, struct sockaddr *addr,socklen_t *addrlen);

sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。

accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。

二、具体编程实现

1.TCP-server

这是一个普通的TCP服务器,可以允许一个客户端进行连接

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <memory.h>
#define MAXN_STR 40
void usage(const char* proc)
{
    printf("[%s],[localip],[localport]\n",proc);
}
int startup(char* ip,int port)
{
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket\n");
        return 0;
    }
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    int opt=1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind\n");
        return 0;
    }
    if(listen(sock,5)<0)
    {
        perror("listen");
        return 0;
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 0;
    }
    int listen_sock=startup(argv[1],atoi(argv[2]));
    char buf[10240];
    struct sockaddr_in client;
    socklen_t len=sizeof(client);
    while(1)
    {
        int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
        if(new_sock<0)
        {
            perror("accept");
            continue;
        }
        close(listen_sock);
        printf("connect... ip is %s,port is %d\n ",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
        while(1)
        {
            ssize_t s=read(new_sock,buf,sizeof(buf)-1);
            if(s>0)
            {
                buf[s]='\0';
                printf("client say:%s\n",buf);
                write(new_sock,buf,strlen(buf));
            }
            else if(s==0)
            {
                printf("client quit\n");
                break;
            }
            else
            {
                break;
            }
        }
        return 0;
    }
    return 0;
}

2.TCP-server多进程版本

可以允许多个客户端同时连接


#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <memory.h>
#define MAXN_STR 40
void usage(const char* proc)
{
    printf("[%s],[localip],[localport]\n",proc);
}
int startup(char* ip,int port)
{
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket\n");
        return 0;
    }
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    int opt=1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind\n");
        return 0;
    }
    if(listen(sock,5)<0)
    {
        perror("listen");
        return 0;
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 0;
    }
    int listen_sock=startup(argv[1],atoi(argv[2]));
    char buf[1024];
    struct sockaddr_in client;
    socklen_t len=sizeof(client);
    while(1)
    {
        int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
        if(new_sock<0)
        {
            perror("accept");
            continue;
        }
	printf("connect... ip is %s,port is %d \n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
        pid_t id=fork();
        if(id>0)
        {
            close(new_sock);
        }
        else if(id==0)
        {
            close(listen_sock);
	        if(fork() > 0)
 		        exit(0);
            while(1)
            {
                ssize_t s=read(new_sock,buf,sizeof(buf)-1);
                if(s>0)
                {
                    buf[s] = 0;
                    printf("client say:%s\n",buf);
                    write(new_sock,buf,strlen(buf));
                }
                else if(s == 0)
                {
                    printf("client quit\n");
                    break;
                }
                else
                {
                    break;
                }
            }
            return 0;
        }
        else
        {
            perror("fork");
            close(listen_sock);
            return 0;
        }
    }
    return 0;
}

3.TCP-server多线程版本


#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
void usage(char* proc)
{
    printf("%s: [localip], [localport]\n", proc);
}
int startup(char* ip, int port)
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket\n");
        return 0;
    }
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = inet_addr(ip);
    int opt = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        perror("bind\n");
        return 0;
    }
    if(listen(sock, 5) < 0)
    {
        perror("listen\n");
        return 0;
    }
    return sock;
}
void *handlerRequest(void* arg)
{
    int new_fd = (int)arg;
    while(1)
    {
        char buf[1024];
        ssize_t s = read(new_fd, buf, sizeof(buf)-1);
        if(s > 0)
        {
            buf[s] = 0;
            printf("Client: %s\n", buf);
            write(new_fd, buf, strlen(buf));
        }
        else
        {
            printf("Read done..., break\n");
            break;
        }
    }
}
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
    }
    int listen_sock = startup(argv[1], atoi(argv[2]));
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    while(1)
    {
        int new_sock = accept(listen_sock, (struct sockaddr*)&client, &len);
        if(new_sock < 0)
        {
            perror("accept");
            continue;
        }
        printf("Get a new connect, %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
        pthread_t id;
        pthread_create(&id, NULL, handlerRequest, (void *)new_sock);
        pthread_detach(id);
    }
    return 0;
}


4.TCP-client客户端部分

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
static void usage(const char* proc)
{
    printf("%s:[service_ip],[service_port]\n",proc);
}
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        return 1;
    }
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("sock");
        return 2;
    }
    struct sockaddr_in remote;
    remote.sin_family = AF_INET;
    remote.sin_port = htons(atoi(argv[2]));
    remote.sin_addr.s_addr = inet_addr(argv[1]);
    if(connect(sock, (struct sockaddr*)&remote, sizeof(remote)) < 0)
    {
        perror("connect");
        return 2;
    }
    while(1)
    {
        char buf[1024];
        printf("Please enter:\n");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf)-1);
        if(s > 0)
        {
            buf[s-1] = 0;
            write(sock, buf, sizeof(buf) - 1);
            ssize_t _s=read(sock, buf, sizeof(buf) - 1);
            if(_s > 0)
            {
                buf[_s] = 0;
                printf("server echo# %s\n", buf);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值