天天看點

多線程Socket伺服器包含TCP與UDP的收發

TCP 和 UDP 伺服器的建立

tcp_udp_server.c

/* tcp_udp_server.c */

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


int udpsockfd = 0;
int tcpsockfd = 0;
int tcpsock_client_fd = 0;

int udpport = 0;
int tcpport = 0;

struct sockaddr_in udp_addr;
struct sockaddr_in tcp_addr;

#define BUFF_LEN 1024
char tcp_recvbuff[BUFF_LEN];



pthread_mutex_t pthreadMutex;
//pthread_mutex_lock(&pthreadMutex);
//pthread_mutex_unlock(&pthreadMutex);

void *thread_tcp_recv(void *arg)
{
    
    int struct_len = 0;
    int numbytes = 0;
    struct sockaddr_in client_addr;
    char buff[BUFF_LEN] = { 0 };
    struct_len = sizeof(struct sockaddr_in);


    tcpsock_client_fd = accept(tcpsockfd, (struct sockaddr *)&client_addr, &struct_len);
    printf("accept return: %d\n", tcpsock_client_fd);
    printf("Get the Client~\n");
    //numbytes = send(tcpsock_client_fd,"Welcome to my server\n",21,0);
    while((numbytes = recv(tcpsock_client_fd, tcp_recvbuff, BUFSIZ, 0)) > 0)
    {
        tcp_recvbuff[numbytes] = '\0';
        printf("TCP Recv[%d]:%s\n",numbytes,tcp_recvbuff);
        if(strcmp(tcp_recvbuff,"tcplink") != 0 )
            send(tcpsock_client_fd,tcp_recvbuff,numbytes,0);
    }
    close(tcpsock_client_fd);
    //close(tcpsockfd);

}

void *thread_tcp_send(void *arg)
{
    int numbytes = 0;
    while(1){
        if( strcmp(tcp_recvbuff,"tcplink") == 0 )
        {

            pthread_mutex_lock(&pthreadMutex);
            
            printf("TCP thread_tcp_send Lock OK\n");

            strcpy(tcp_recvbuff,"tcplinkkkkkkkkkkkkkkkkkkkk");

            numbytes = strlen(tcp_recvbuff);
            if( send(tcpsock_client_fd,tcp_recvbuff,numbytes,0) < 0 )
            {
                perror("TCP write send error");                
            }
            //memset(tcp_recvbuff,0 ,sizeof(tcp_recvbuff));
            pthread_mutex_unlock(&pthreadMutex);
            printf("TCP thread_tcp_send unLock OKKKK\n");
        }        
    }
}

int start_TCP_Service(int port)
{
    int struct_len;

    char buff[BUFF_LEN];

    tcp_addr.sin_family = AF_INET;    
    tcp_addr.sin_port = htons(port);
    tcp_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(tcp_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);

    tcpsockfd = socket(AF_INET, SOCK_STREAM, 0);
    if( tcpsockfd < 0)
    {
        perror("tcpsockfd");
    }
    // 進行連接配接确認
    while(  bind(tcpsockfd, (struct sockaddr *)&tcp_addr, struct_len) == -1 );
    printf("Tcp Bind Success!\n");

    while( listen(tcpsockfd, 10) == -1 );
    printf("Tcp  Listening....\n");
    printf("Tcp  Ready for Accept,Waitting...\n");


    //啟動線程接收或者發送
    pthread_t tcp_thread_send;
    pthread_t tcp_thread_recv;

    if( pthread_create(&tcp_thread_send, NULL, thread_tcp_send,NULL))
    {
        perror("TCP Create thead_updsend failed\n");//建立錯誤時執行
    }

    if( pthread_create(&tcp_thread_recv, NULL, thread_tcp_recv,NULL))
    {
        perror("TCP Create thead_udprecv failed\n");//建立錯誤時執行
    }

    return 0;
}




void *thead_updsend(void *arg)
{
    #if 0
    char buf[1024] = { 0 };
    while(1)
    {
        udp_addr.sin_family = AF_INET;
        udp_addr.sin_port = htons(udpport);
        udp_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        //scanf("%s",buf);
        memcpy(buf,"hello word",10);
        if( strlen(buf) > 0)
        {
            pthread_mutex_lock(&pthreadMutex);
            printf("UDP send buf=[%s] \n",buf);
            sendto(udpsockfd,buf,strlen(buf),0,(struct sockaddr *)&udp_addr,sizeof(udp_addr));
            memset(buf , 0 ,sizeof(buf));
            pthread_mutex_unlock(&pthreadMutex);
        }
         
        sleep(1);
    }
    #endif
}

void *thead_udprecv(void *arg)
{
       
    struct sockaddr_in client;
    int rLen,len,PORT_INT = 0,count = 0;
	char buff[BUFF_LEN] = {0};    
	char *IP_STR = NULL;    
	len = sizeof(client);    
    printf("UDP len=%d\n",len);
	while(1){        
        
		rLen = recvfrom(udpsockfd,buff,BUFF_LEN,0,(struct sockaddr *)&client,&len);        
		IP_STR = (char *)inet_ntoa(client.sin_addr);        
		PORT_INT = ntohs(client.sin_port);        
		printf("UDP %d Received Address:%s:%d\n",count,IP_STR,PORT_INT);        
		printf("UDP %d Received Message[%d]:%s\n",count++,rLen,buff);        
		printf("\n");        
		sendto(udpsockfd,buff,rLen,0,(struct sockaddr *)&client,len);        
		memset(buff,0,BUFF_LEN);            
	}

}


int strt_UDP_Service(int port)
{   
    #if 1
    int s = 0;    
	struct sockaddr_in addr_serv,addr_clie;    
	udpsockfd = socket(AF_INET,SOCK_DGRAM,0);    
	memset(&addr_serv,0,sizeof(addr_serv));    
	addr_serv.sin_family = AF_INET;    
	addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);    
	addr_serv.sin_port = htons(port);    

    // struct timeval tv;
    // tv.tv_sec  = 1;
    // tv.tv_usec = 0;//200000; // 200ms
    // setsockopt(udpsockfd,SOL_SOCKET, SO_RCVTIMEO,(const char *)&tv,sizeof( struct timeval));   //設定逾時


	if( bind(udpsockfd,(struct sockaddr *)&addr_serv,sizeof(addr_serv)) )
    {
        printf("UDP failed to bind socket on port=%d\n",port);
        close(udpsockfd);
        return -1;
    }
    printf("UDP server create OK!\n");


    int optVal;
    int optLen = sizeof(int);

    getsockopt(udpsockfd, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, &optLen);
    printf("The max length is %d\n", optVal);

    pthread_t udp_thread_send;
    pthread_t udp_thread_recv;

    if( pthread_create(&udp_thread_send, NULL, thead_updsend,NULL))
    {
        perror("UDP Create thead_updsend failed\n");//建立錯誤時執行
    }

    if( pthread_create(&udp_thread_recv, NULL, thead_udprecv,NULL))
    {
        perror("UDP Create thead_udprecv failed\n");//建立錯誤時執行
    }

    #endif

    return 0;
}


int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        printf("please input PORT just like  %s 8889\n",argv[0]);
        return 0;
    }

    udpport = atoi(argv[1]);
    tcpport =  atoi(argv[1]);
    printf("udpport PORT = %d\n",udpport);
    
    //初始化互斥鎖
    pthread_mutex_init(&pthreadMutex,NULL);

    start_TCP_Service(tcpport);
    strt_UDP_Service(udpport);

    printf("main ...\n");
    pthread_exit(NULL);//(1)結束主
    printf("main stop...\n");

    //銷毀互斥鎖
    pthread_mutex_destroy(&pthreadMutex);

    return 0;
}
           

編譯指令為:

gcc tcp_udp_server.c -o tcp_udp -lpthread
           

TCP 用戶端代碼如下

tcp_client.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define SERVER_PORT 8889

int main(int argc,char *argv[])
{
    int sockfd,numbytes;
    char buf[BUFSIZ];
    struct sockaddr_in their_addr;
    printf("break!");
    //如果得到傳回值不為0,說明socket沒建立成功,繼續等待,與服務端無關
    while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1);
    printf("We get the sockfd~\n");
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(SERVER_PORT);
    // 伺服器 Socket 的 IP 位址
    their_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    bzero(&(their_addr.sin_zero), 8);
    
    while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
    
    printf("Get the Server OK~\n");

    while(1)
    {
        printf("Enter something:");
        
        scanf("%s\n",buf);
        printf("scanf: %s\n", buf);
        if( strlen(buf) > 0)
        {
            numbytes = send(sockfd, buf, strlen(buf), 0);
            printf("send numbytes: %d\n", numbytes);
        }
        else{ continue; }

        numbytes=recv(sockfd,buf,BUFSIZ,0);  
        printf("recv numbytes: %d\n", numbytes);
        buf[numbytes]='\0'; 
        printf("received:%s\n",buf);  

        memset(buf, 0 ,sizeof(buf));
    }
    close(sockfd);
    return 0;
}
           

編譯指令為

gcc tcp_client.c -o tcpclient
           

UDP 用戶端代碼如下

udp_client.c

//udp_client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>


#define PORT_SERV 8889
#define BUFF_LEN 1024
#define LINK_IP "127.0.0.1"

static void UDP_client(int udpsock,struct sockaddr_in *client)
{
	int recvLen = 0;
    char RecBuff[BUFF_LEN]="\n";
    char SendBuff[BUFF_LEN] = {0};
    int n;
    struct sockaddr_in from;
    int len = sizeof(*client);
    printf("please input message!\n");
    while(1){
        n = read(0,SendBuff,BUFF_LEN);
        SendBuff[n++] = '\0';
        sendto(udpsock,SendBuff,n,0,(struct sockaddr *)client,len);
		
		recvLen = recvfrom(udpsock,RecBuff,BUFF_LEN,0,(struct sockaddr*)&from,&len);
        if( recvLen > 0 )
			printf("recved[recvLen]:%s \n",RecBuff , recvLen);
    }
}


int main(int argc,char **argv)
{
    int udpsock;
    struct sockaddr_in addr_serv,addr_clie;
    char *msg;
    /*
    if(argc != 3){
        printf("parameter is error!\n");
        printf("format:ip port\n");
        return -1;
    }
    */
    udpsock = socket(AF_INET,SOCK_DGRAM,0);
    memset(&addr_clie,0,sizeof(addr_clie));
    addr_clie.sin_family = AF_INET;
   
    /*inet_addr(LINK_IP); inet_addr(argv[1])*/   
    addr_clie.sin_addr.s_addr = htonl(INADDR_ANY);
   
    /*htons(atoi(argv[2]));*/
    addr_clie.sin_port = htons(PORT_SERV);


    UDP_client(udpsock,&addr_clie);


    close(udpsock);
    return 0;
}
           

編譯指令如下

gcc udp_client.c -o udpclient
           

首先啟動伺服器

./tcp_udp 8889

然後分别執行

./tcp_client 

./udp_client 

可同時完成 UDP 和TCP的資訊處理

繼續閱讀