linux笔记之socket编程实现双向通信

linux笔记之socket编程实现双向通信

  • 前言
    • 服务机
    • 客户机:
    • 注意

前言

在完成老师的linux课堂作业时,获益良多,感谢老师的指导和帮助,同时分享一下我的代码以及一些注意事项,希望大家都能少走一些弯路,也欢迎大家进行指导或者探讨。

效果图: linux笔记之socket编程实现双向通信_第1张图片

客户机样式为./可执行文件 默认网络ip

服务机

服务机端一直等待客户端的连接请求,接受连接后,则服务机端会创建一个线程用于发送数据,另一个线程用于接收数据,当发送88时退出程序.

#include  <sys/types.h>
#include  <sys/socket.h>
#include  <stdio.h>
#include  <netinet/in.h>
#include  <arpa/inet.h>
#include  <unistd.h>
#include  <string.h>
#include  <netdb.h>
#include  <sys/ioctl.h>
#include  <termios.h>
#include  <stdlib.h>
#include  <sys/stat.h>
#include  <fcntl.h>
#include  <signal.h>
#include  <sys/time.h>
#include <pthread.h>

#define LENGTH 512 //发送数据长度
#define PORT 5000 //套接字所用端口号
#define BACKLOG 10 //最大监听数

void* recv1(int nsockfd)
{
	int num;
	char recvBuf[LENGTH];
	memset(recvBuf,0,sizeof(recvBuf));
	
	while(1)
	{
		num = recv(nsockfd,recvBuf,sizeof(recvBuf),0);
		if(num > 0)
		{
			printf("host receive: %s \n", recvBuf);
		}
		else break;
	}
}

void* send1(void* args)
{
	int sockClient1;
	char buff1[LENGTH];

	sockClient1 = *((int*)args);//套接字
	while(1)
	{
		
		scanf("%s",buff1);
		if(buff1 == " ")
		{
			break;
		}
		int e = send(sockClient1,buff1,sizeof(buff1),0);
		if(e == -1)
		{
			printf("发送失败!");
			break;
		}
		printf("host send: %s\n", buff1);
		if(strcmp(buff1,"88") == 0)
		{
			close(sockClient1);
			exit(1);
		}
	}
	
}
int main(void)
{
	int sockfd; //建一个套接字,用于监听 
	int nsockfd;//建立通讯的套接字
	int sin_size;  //结构体长度
	int ret;//发送线程的返回
	struct sockaddr_in addr_host;//本机地址信息
	struct sockaddr_in addr_remote;//客户端地址信息
	char buf[]= {"Host: hello, I'm a server !(QAQ)!"};

	if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("ERROR: Failed to obtain Socket Despcritor.\n");
		return 0;
	}
	else
	{
		printf("OK: Bind the Port %d sucessfully.\n",PORT);	
	}

	bzero(&addr_host, sizeof(struct sockaddr_in));//清零后再初始化端口
	addr_host.sin_family = AF_INET;
	addr_host.sin_port = htons(PORT);
	addr_host.sin_addr.s_addr = htonl(INADDR_ANY);

	if(bind(sockfd,(struct sockaddr*)&addr_host,sizeof(struct sockaddr)) == -1)
	{
		printf ("ERROR: Failed to bind Port %d.\n",PORT);
		return (0);
	}
	 else
    {
        printf("OK: Bind the Port %d sucessfully.\n",PORT);
    }
	
	if(listen(sockfd,BACKLOG) == -1)    
    {  
        printf ("ERROR: Failed to listen Port %d.\n", PORT);
        return (0);
    }
    else
    { 
        printf ("OK: Listening the Port %d sucessfully.\n", PORT);
    }
    
    while(1)
    {
    	/*等待客户请求*/
    	sin_size = sizeof(struct sockaddr_in);
    	if((nsockfd = accept(sockfd,(struct sockaddr *)&addr_remote,&sin_size))== -1)
    	{
    		printf ("ERROR: Obtain new Socket Despcritor error.\n");
    		continue;
    	}
    	else
        {
        	/*inet_ntoa将一个网络字节序的IP地址(结构体型)转化为点分十进制(字符串)*/
            printf ("OK: Server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr)); 
        }
        /*发送数据*/
        int iSend = send(nsockfd,buf,sizeof(buf),0);
        if(iSend == -1)
        {
        	printf("发送失败\n");
        	break;
        }
        pthread_t tids[2];
        if((ret = pthread_create(&tids[0],NULL,send1,(void*)&nsockfd)) != 0)
        {
        	printf("pthread_creat error\n");
        }
        recv1(nsockfd);
        close(nsockfd);
    }
    close(sockfd);
   
}

客户机:

客户机端先建立socket,通过connect()请求连接,建立连接成功后,客户机端会创建一个线程用于发送数据,另一个线程用于接收数据,当接收到88时退出程序.

#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>
#include <pthread.h>

#define LENGTH 512 //发送数据长度
#define PORT 5000          //套接字所用端口号
void* recv1(int nsockfd)
{
	int num;
	char recvBuf[LENGTH];
	memset(recvBuf,0,sizeof(recvBuf));
	
	while(strcmp(recvBuf,"88") != 0)
	{
		num = recv(nsockfd,recvBuf,sizeof(recvBuf),0);
		if(num > 0)
		{
			printf("client receive: %s \n", recvBuf);
		}
		else break;
	}
}

void* send1(void* args)
{
	int sockClient1;
	char buff1[LENGTH];
	
	sockClient1 = *((int*)args);
	while(1)
	{
		scanf("%s",buff1);
		if(buff1 == " ")
		{
			break;
		}
		int e = send(sockClient1,buff1,sizeof(buff1),0);
		if(e == -1)
		{
			printf("发送失败!");
			break;
		}
		printf("client send: %s\n",buff1);
	}
	
}
int main(int argc,char *argv[]) //从终端里读取参数,
{
	int sockfd;
	int ret; //创建线程的返回值
	char buff[LENGTH];
	memset(buff,0,sizeof(buff));
	struct sockaddr_in remote_addr;
	
	if(argc != 2)
	{
		printf ("error: 请输入Client HOST IP (例如: ./client 192.168.0.94).\n");
		return 0;
	}
	
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("ERROR: Failed to obtain Socket Descriptor!\n");
        return (0);
    }
    bzero(&remote_addr,sizeof(remote_addr));			//清零后再初始化端口
    remote_addr.sin_family = AF_INET;                   // Protocol Family
    remote_addr.sin_port = htons(PORT);                 // Port number
    inet_pton(AF_INET, argv[1], &remote_addr.sin_addr); // Net Address  
    
    if (connect(sockfd, (struct sockaddr *)&remote_addr,  sizeof(struct sockaddr)) == -1) 
    {
        printf ("ERROR: Failed to connect to the host!\n");
        return (0);
    }  
    else
    {	
        printf ("OK: Have connected to the %s\n",argv[1]);
    	pthread_t tids[2];
    	ret = pthread_create(&tids[0],NULL,send1,(void*)&sockfd);
    	if(ret != 0)
    	{
    		printf("pthread_creat error\n");
    	}
        recv(sockfd, buff,sizeof(buff), 0);
        printf("%s\n",buff);
	}
    recv1(sockfd);
    //send1((void*)&sockfd);
    close(sockfd);
}

注意

  1. 编译时,因为pthread.h不是linux默认的库,所以需要对其进行手动链接,如:
    gcc -o client client.c -lpthread
  2. 当你采用的TCP通信是crtl + z 停止退出程序时,此时其端口号没有关闭,可以用netstat -nultp命令查看占用端口号对应的进程号
    linux笔记之socket编程实现双向通信_第2张图片

再用kill -9 端口号对应的PID,杀死该进程,这样可以防止端口号被占用,出现bind绑定失败的情况。

你可能感兴趣的:(笔记,linux,socket)