socket

利用socket套接字聊天


套接字地址结构体

struct sockaddr_in{
	unsigned short sin_family;
	unsigned short sin_port;//端口
	struct in_addr sin_addr;//ip
	unsigned char  sin_zero[8];
};


另外一个通用的结构
struct sockaddr{
    unsigned short sa_family;
    char           sa_data[14];
};



//存放ip的结构体
struct in_addr{
    unsigned int a_addr;
};//将ip放在一个结构体中,是套接字接口早期不幸的产物



以上结构体都在netinet/in.h
无论何时我们都可以将sockaddr_in强制转换为sockaddr

typedef struct sockaddr SA;

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);
int bind(int sockfd,struct sockaddr *my_addr,int addrlen);
int listen(int sockfd,int backlog);
int accept(int listenfd,struct sockaddr *addr,int *addrlen);





我们发现将socket和connect封装成一个open_clientfd函数是很方便的,客户端可以用它来和服务器建立连接

同样,将socket、bind、listen函数结合成一个open_listenfd的函数,服务端可以创建一个监听描述符。
--->
我将if((clientfd=socket(AF_INET,SOCK_STREAM,0))<0)写成了if(clientfd=socket(AF_INET,SOCK_STREAM,0)<0)导致了严重的错误
注意端口号是否被占用
<---

------------分割------------open.h

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>//use inet_aton();
#include <netinet/in.h>//use htons();
#include <sys/types.h>
#include <sys/socket.h>//use socket() connect()
typedef struct sockaddr SA;
int open_clientfd(char *ip,int port)
{
	int clientfd;
	struct sockaddr_in serveraddr;
	bzero((char *)&serveraddr,sizeof(serveraddr));//设为0
	if((clientfd=socket(AF_INET,SOCK_STREAM,0))<0)
		return -1;
	
	inet_aton(ip,&serveraddr.sin_addr);//ip
	serveraddr.sin_port=htons(port);//port
	serveraddr.sin_family=AF_INET;//family

	if(connect(clientfd,(SA*)&serveraddr,sizeof(serveraddr))<0)
		return -2;
	return clientfd;
}
int open_listenfd(int port)
{
	int listenfd;
	struct sockaddr_in serveraddr;
	bzero((char *)&serveraddr,sizeof(serveraddr));
	if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
		return -1;

	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=INADDR_ANY;
	serveraddr.sin_port=htons(port);

	if(bind(listenfd,(SA*)&serveraddr,sizeof(serveraddr))<0)
	 	return -2;
	//bind(listenfd,(SA*)&serveraddr,sizeof(serveraddr));
	printf("%d\n",listenfd);
	if(listen(listenfd,1024)<0)return -3;

	return listenfd;
}


---------------------------------open.h



第一版:客服端一直发送,服务端显示
 
   客服端
----------------------------------echoclient.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "open.h"
#define max_long 1000
int main()
{
	int clientfd;
	clientfd=open_clientfd("127.0.0.1",1111);
	printf("%d\n",clientfd);

	while(1)
	{
		char buf[max_long];
		bzero(&buf,max_long);
		fgets(buf,max_long,stdin);
		send(clientfd,buf,strlen(buf)-1,0);

	}
	close(clientfd);
	return 0;
}

----------------------------------echoclient.c

  服务端
----------------------------------echoserver.c
#include <stdio.h>
#include <unistd.h>
#include "open.h"
#include <string.h>
#define max_long 1000
void echo(int connfd);
int main()
{
	int listenfd;
	listenfd=open_listenfd(1111);

	printf("%d\n",listenfd );

	int connfd,addrlen;
	struct sockaddr_in clientaddr;
	while(1)
	{
		addrlen=sizeof(clientaddr);
		connfd=accept(listenfd,(SA *)&clientaddr,&addrlen);
		echo(connfd);
		close(connfd);
	}
	return 0;
}
void echo(int connfd)
{
	while(1)
	{
		char buf[max_long];
		bzero(&buf,max_long);
		recv(connfd,buf,max_long,0);
		printf("%s\n",buf);
	}
}

第二版 :可以通过进程的创建,一个用来接受,一个用来发送
但是存在两个问题:
1 当直接杀死某一端的时候,另一端会一直循环输出

2 没有妥善的出来子父进程之间的关系

  客服端
----------------------------------echoclient.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "open.h"
#define max_long 1000
int main()
{
	int clientfd;
	char *ip="127.0.0.1";
	clientfd=open_clientfd(ip,1111);
	//printf("%d\n",clientfd);
	if(clientfd>=0)
	printf("已经连接上%s\n",ip);


	pid_t pid;
	pid=fork();
	if(pid==0)//接受
	{
		while(1)
		{
			char buf[max_long];
			bzero(&buf,max_long);
			int n=recv(clientfd,buf,max_long,0);
			if(buf[0]=='q')break;
			printf("%s\n",buf);
		}
	}
	else//发送
	{
		while(1)
		{
			char buf[max_long];
			bzero(&buf,max_long);
			fgets(buf,max_long,stdin);
			send(clientfd,buf,strlen(buf)-1,0);
		}
	}

	close(clientfd);
	return 0;
}
----------------------------------echoclient.c

  服务端
----------------------------------echoserver.c
#include <stdio.h>
#include <unistd.h>
#include "open.h"
#include <string.h>
#define max_long 1000
void echo(int connfd);
int main()
{
	int listenfd;
	listenfd=open_listenfd(1111);

	//printf("%d\n",listenfd );

	int connfd,addrlen;
	struct sockaddr_in clientaddr;
	while(1)
	{
		printf("等待别人连接:\n");
		addrlen=sizeof(clientaddr);
		connfd=accept(listenfd,(SA *)&clientaddr,&addrlen);
		printf("%s已连接\n",inet_ntoa(clientaddr.sin_addr));
		int pid;
		pid=fork();
		if(pid==0)//发送
		{
			while(1)
			{
				char buf[max_long];
				bzero(&buf,max_long);
				fgets(buf,max_long,stdin);
				send(connfd,buf,strlen(buf)-1,0);	
			}
		}
		else//接受
		{
			echo(connfd);
		}
		close(connfd);
	}
	return 0;
}
void echo(int connfd)
{
	while(1)
	{
		char buf[max_long];
		bzero(&buf,max_long);
		int n=recv(connfd,buf,max_long,0);
		if(buf[0]=='q')
		{break;}
		printf("%s\n",buf);
	}
}


这里是web服务器第一版

    通过1118端口,简单的响应浏览器的访问

#include <stdio.h>
#include <unistd.h>
#include "open.h"
#include <string.h>
#define max_long 10000
typedef struct sockaddr SA;
int main()
{
	int listenfd;
	listenfd=open_listenfd(1118);
	if(listenfd<0)return -1;
	int connfd,addrlen;
	struct sockaddr_in clientaddr;
	while(1)
	{
		printf("waite connect...\n");
		addrlen=sizeof(clientaddr);
		connfd=accept(listenfd,(SA *)&clientaddr,&addrlen);
		printf("connect success\n");

		FILE *client=fdopen(connfd,"w");
	
		char buf[max_long];
		
		//发送给浏览器阅读的头信息
		fprintf(client,"HTTP/1.1 200 OK\r\nServer:Testhttp server\r\nContent-length:1000\r\nContent-type:text/html\r\n\r\n");
		//需要显示的内容		
		fprintf(client,"<html><title>test</title><body><p>this is a p<a href="">99999</a></p></body></html>");
		//sleep(10);
		fclose(client);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值