Linux socket网络编程基础 tcp协议和udp协议

Socket TCP网络通信编程

首先,服务器端需要做以下准备工作:

(1)调用socket()函数。建立socket对象,指定通信协议。

(2)调用bind()函数。将创建的socket对象与当前主机的某一个IP地和端口绑定。

(3)调用listen()函数。使socket对象处于监听状态,并设置监听队列大小。

客户端需要做以下准备工作:

(1)调用socket()函数。建立socket()对象,指定相同通信协议。

(2)应用程序可以显式的调用bind()函数为其绑定IP地址和端口,当然,也可以将这工作交给TCP/IP协议栈。

接着建立通信连接:

(1)客户端调用connect()函数。向服务器端发出连接请求。

(2)服务端监听到该请求,调用accept()函数接受请求,从而建立连接,并返回一个新的socket文件描述符专门处理该连接。

然后通信双方发送/接收数据:

(1)服务器端调用write()或send()函数发送数据,客户端调用read()或者recv()函数接收数据。反之客户端发送数据,服务器端接收数据。

(2)通信完成后,通信双方都需要调用close()或者shutdown()函数关闭socket对象。

 

类比电话通信,面向连接的socket通信实现图

 

Linux socket网络编程基础 tcp协议和udp协议

 

展示一个代码示例:

服务端:

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

static void usage(const char *proc)
{
    printf("Please use :%s [IP] [port]\n",proc);
}

void thread_run(void *arg)
{
    printf("creat a new thread\n");
    int fd = (int)arg;
    char buf[1024];

    while(1){
        memset(buf,'\0',sizeof(buf));
        ssize_t _s = read(fd,buf,sizeof(buf) - 1);
        if(_s > 0){
            buf[_s] = '\0';
            printf("client say : %s\n",buf);
        }   
        memset(buf,'\0',sizeof(buf));
        printf("please Enter: ");
        fflush(stdout);
        ssize_t _s2 = read(0,buf,sizeof(buf) - 1);
        if(_s2 > 0){
            write(fd,buf,strlen(buf));
        }
    }
}

int main(int argc,char *argv[])
{
    if(argc != 3){
        usage(argv[0]);
        exit(1);
    }

    //1.creat socket

    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0){
        perror("creat socket error\n");
        return 1;
    }

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

    //2.bind

    if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){
        perror("bind error\n");
        close(sock);
        return 2;
    }
 
    //3.listen

    if(listen(sock,10) < 0){
        perror("listen error\n");
        close(sock);
        return 3;
    }

    printf("bind and listen success!wait accept...\n");
   
    //4.accept

    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);
    while(1){

        int fd = accept(sock,(struct sockaddr*)&peer ,&len);

        if(fd < 0){
            perror("accept error\n");
            close(sock);
            return 4;
        }
       
        printf("get connect,ip is : %s port is : %d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));

        pthread_t id;
        pthread_create(&id,NULL,thread_run,(void*)fd);

        pthread_detach(id);

    }
    close(sock);
    return 0;
}

客户端:

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

static void usage(const char *proc)
{
    printf("please use : %s [ip] [port]\n",proc);
}
int main(int argc,char *argv[])
{
    if( argc != 3 ){
        usage(argv[0]);
        exit(1);
    }
   
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0){
        perror("socket error");
        return 1;
    }

    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]);


    int ret = connect(sock,(struct sockaddr*)&remote,sizeof(remote));
    if(ret < 0){
        printf("connect failed:%s\n",strerror(errno));
        return 2;
    }
   
    printf("connect success!\n");

    char buf[1024];
    while(1){
        memset(buf,'\0',sizeof(buf));
        printf("please enter:");
        fflush(stdout);
        ssize_t _s = read(0,buf,sizeof(buf)-1);
        if(_s > 0){
            buf[_s - 1] = '\0';
            write(sock,buf,strlen(buf));
            _s = read(sock,buf,sizeof(buf)-1);
            if(_s > 0){
                if(strncasecmp(buf,"quit",4) == 0){
                    printf("qiut\n");
                    break;
                }
                buf[_s -1] = '\0';
                printf("%s\n",buf);
            }
        }
    }
    close(sock);
    return 0;
}

UDP网络通信编程

 客户不与服务器建立链接,而是管使用sendto函数给服务器发送数据报,其中必须指定目的地址(即服务器地址)作为参数。类似的,服务器不接受来自客户的连接,而只管调用

revcfrom函数等待来自某个客户数据的到达。revcfrom将与所接受到的数据报一道返回客户的协议地址,因此服务器可以把响应发送给正确的客户。

 

Linux socket网络编程基础 tcp协议和udp协议

 int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);

int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);

第一个参数为发送的目标socket对象。

第二个参数为欲发送的数据信息。

第三个参数为发送数据的大小。

第四个参数为flags,如send函数所示。

第五个参数欲发送数据的目标地址,其结构体前面已经介绍。

第六个参数为此结构体的大小。

服务端代码示例:

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

int main(int argc,char *argv[])
{
    if(argc != 3){
        printf("Please Enter: %s [ip] [port]",argv[0]);
        return 1;
    }
   
    int sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock < 0){
        perror("socket error");
        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(bind(sock,(struct sockaddr*)&remote,sizeof(remote)) < 0){
        perror("bind error");
        return 3;
    }

    int done = 0;
    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);

    char buf[1024];
    while(!done){
        memset(buf,'\0',sizeof(buf));
        printf("Please Enter:");
        fflush(stdout);
        ssize_t _s = read(0,buf,sizeof(buf)-1 );
        if(_s > 0){
            buf[_s -1] = '\0';
            sendto(sock,buf,sizeof(buf),0,(struct sockaddr*)&remote,sizeof(remote));

            memset(buf,'\0',sizeof(buf));
            recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)&peer,&len);
            printf("server echo %s,socket :&s:&d\n",buf,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
        }
    }
    return 0;
}

客户端代码示例:

相关推荐