方案一TCP 完成聊天室的编写

完成聊天室 需要聊天 那就要建立连接 建立连接后 就发送信息

建立连接 和 发送信息 需要什么函数 ?

服务器 客户端 各自需要什么?

服务器:

1.1  socket :创建一个Socket 用以监听 (一个空的通道  一头将要连服务器 一头将要连客户)

1.2  Bind :绑定 IP 和 端口号

1.3  Listen :监听  两个参数  参数1 :socket 那个通道

                                              参数2 :数字  监听队列的大小 : 同一时刻 允许的最大连接数

1.4  accept :接受客户发起的连接  参数 1 :  socket

                                                         参数 2 :客户端的IP 和端口...

                                                         参数 3 :结构体的长度

1.5  send 和 recv

客户端:

2.1  socket : 创建一个socket

2.2  connect : 连接

 

具体函数都可以利用man (manual)手册进行查询 :例如man 2 socket 记得把其中的头文件加入自己的代码中

标准的man手册主要分为8个章节,分别为:

1 User Commands // 用户命令

2 System Calls // 系统调用

3 C Library Functions // C函数库调用

4 Devices and Special Files // 设备文件和特殊文件

5 File Formats and Conventions // 配置文件及格式

6 Games et. Al. // 游戏

7 Miscellanea // 杂项

8 System Administration tools and Deamons // 管理类命令

使用格式:

man [章节] COMMAND

q Q ZZ 退出

 

基本的函数

TCPserver.c :

1.1  Socket

创建一个int 型socketid接socket的返回值 返回值是一个文件描述符

一般的,文件描述符: 0 标准输入 1 标准输出 2 标准错误输出

0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr,

0就是stdin,1就是stdout,2就是stderr

(函数原型)int socket(int domain, int type, int protocol);

Domain: 地址族协议 我们一般用PF_INET (ipv4协议)

Type: 套接字的类型 (TCP用SOCK_STREAM)(UDP用 SOCK_DGRAM)

前面博客中已经告知所有相关知识点

Protocol: 一般默认为0 这个参数是由前面两个就决定好的 不需要特意再去指定

 

1.2  Bind

创建一个int型 ret 接bind的返回值 返回值 代表是否绑定成功

(函数原型)int bind ( int  sockfd,  const  struct  sockaddr  *my_addr,  socklen_t addrlen);

Sockfd: 文件描述符 指定绑定谁 (在服务器创建了socket之后当然先把自己绑在通道的一端,等待客户向自己发起连接)

my_addr: 是一个结构体:struct  sockaddr

Addrlen: 是第二个参数 结构体的大小

 

**所以在第二个参数这里 我们就需要在开始bind前创建一个结构体

Struct   sockaddr_in   server_addr;

并且对这个结构体 内部的数据 进行初始化

memset(&server_addr, 0, sizeof(struct sockaddr_in)); //清空原始数据 防止出错(这个函数需要+string.h头文件)

server_addr.sin_family = AF_INET; //地址族协议 用ipv4

server_addr.sin_port = PORT; //指定端口号 PORT自己在最开始指定(我是8888)

server_addr.sin_addr.s_addr = inet_addr("192.168.222.128");

//指定服务器的ip地址为 192.168.222.128

//这里 因为系统内存放的数据是二进制(长整型)所以用到转换函数 inet_addr( )

//函数原型in_addr_t inet_addr(const char* strptr);

//返回:若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址

 

1.3  Listen

创建一个int型 ret 接Listen的返回值 返回值 代表是否绑定成功

(函数原型)int listen(int sockfd, int backlog);

Sockfd: 监听服务器创建的通道上是否有请求

Backlog: 同一时刻 允许的最大连接数

 

1.4  Accept

创建一个int型 fd [ i ]  接Listen的返回值 返回值 代表接受到哪个客户端发送来的请求

//fd [ i ] 因为你接受到的客户请求可能不止一个 你需要把他们都记下来 一个个处理

//但是fd [ i ] 的值是从4开始的 前面说过了 012 标准--输入、输出、错误输出 3 是自己创建的sockfd

(函数原型)int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Sockfd: 文件描述符 指示哪个客户的文件描述符有变化

ddr: 是一个结构体:struct  sockaddr 代表接受到的 客户的地址

Addrlen: 是第二个参数 结构体的大小

 

**所以在第二个参数这里 我们同样要在开始前创建一个结构体

Struct   sockaddr_in   client_addr;

memset(&server_addr, 0, sizeof(struct sockaddr_in)); //清空原始数据 防止出错

 

1.5  创建线程pthread_create

创建一个int型 ret接pthread_create的返回值 返回值 代表线程是否创建成功

(函数原型)int pthread_create(pthread_t *restrict thread,

               const pthread_attr_t *restrict attr,

               void *(*start_routine)(void*), void *restrict arg);

restrict thread:开始就创建一个pthread_t tid[100]; 用以创建线程 因为一次接受就需要一次线程的创建;

restrict attr: 用于指定各种不同的线程属性,默认为NULL

*(*start_routine)(void*): 线程创建后 用此处对应的函数 进行线程的处理(完成此线程需要的功能)

restrict arg: &fd[ i ]  : 最后一个参数是运行函数的参数 哪个客户调用这个函数了

 

 

TCPclient.c

2.1 soket()

同上面服务器的一样

2.2 connect()

(函数原型)int  connect(int  sockfd,  const  struct sockaddr *serv_addr, socklen_t  addrlen);

Socket: 很明显和上面差不多 这里的sockfd就是客户自己创建的

serv_addr: 和上面一样 自己一开始就创建一个结构体就行 记得也要初始化

Addrlen: 大小就是结构体的大小

 

 

最后就是写一个 send 一个recv 函数用以接收和发送信息了。

 

TCPserver.c

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

#define PORT 8888

struct info
{
	char buf[100];
	int to_fd;
};
struct info SendBuf;

void *HandlerClientThread(void *arg)
{
	int ret;

	while (1)
	{
		ret = recv(*(int *)arg, &SendBuf, sizeof(SendBuf), 0);
		if (-1 == ret)
		{
			perror("recv");
			return;
		}
		
		//printf("Receive From %d : %s\n", *(int *)arg, buf);
		
		ret = send(SendBuf.to_fd, &SendBuf, sizeof(SendBuf), 0);
		if (-1 == ret)
		{
			perror("send");
			return;
		}

		memset(&SendBuf, 0, sizeof(SendBuf));
	}
	
}

int main()
{
	int sockfd, ret, fd[100] = {0}, length, i = 0;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	char buf[100] = {0};
	pthread_t tid[100];

	printf("START SERVER!\n");

	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("sockfd");
		exit(1);
	}

	int opt = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	memset(&server_addr, 0, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = PORT;
//	server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	server_addr.sin_addr.s_addr = inet_addr("192.168.222.128");
	

	ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (-1 == ret)
	{
		perror("bind");
		exit(1);
	}
	
	printf("WAITTING FOR CONNECT...\n");
	
	while(1)
	{
		ret = listen(sockfd, 5);
		if (-1 == ret)
		{
			perror("listen");
			exit(1);
		}

		length = sizeof(client_addr);
		fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length);
		if (-1 == fd[i])
		{
			perror("accept");
			exit(1);
		}
	
		printf("ACCEPT %d ,Port = %d!\n", fd[i], client_addr.sin_port);
	
		ret = pthread_create(&tid[i], NULL, HandlerClientThread, (void *)&fd[i]);
		if (0 != ret)
		{
			perror("create");
			exit(1);
		}
		
		i++;
	}

	return 0;
}

TCPclient.c

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

#define PORT 8888

struct info
{
	char buf[100];
	int to_fd;
};

struct info SendBuf;


void *MyReceive(void *arg)
{
	int ret;
	
	while (1)
	{
		ret = recv(*(int *)arg, &SendBuf, sizeof(SendBuf), 0);
		if (-1 == ret)
		{
			perror("recv");
			return;
		}
		printf("\t\t\t%s\n", SendBuf.buf);
		memset(&SendBuf, 0, sizeof(SendBuf));
	}
}



//int main()
int main(int argc, char *argv[])
{
	int sockfd, ret;
	struct sockaddr_in server_addr;
	char buf[100] = {0};
	pthread_t tid;

	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("socket");
		exit(1);
	}
	memset(&server_addr, 0, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = PORT;
//	server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);//自己从运行程序的时候传进来
	
	ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (-1 == ret)
	{
		perror("connect");
		exit(1);
	}

	ret = pthread_create(&tid, NULL, MyReceive, (void *)&sockfd);
	if (0 != ret)
	{
		perror("create");
		exit(1);
	} 

	while(1)
	{
		scanf("%s %d", SendBuf.buf, &SendBuf.to_fd);
		ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
		if (-1 == ret)
		{
			perror("sand");
			exit(1);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38313246/article/details/81511049