示例#1
0
int 
skynet_socket_bind(struct skynet_context *ctx, int fd) {
	uint32_t source = skynet_context_handle(ctx);
	return socket_server_bind(SOCKET_SERVER, source, fd);
}
示例#2
0
int 
skynet_socket_connect(struct skynet_context *ctx, const char *host, int port) {
	uint32_t source = skynet_context_handle(ctx);
	return socket_server_connect(SOCKET_SERVER, source, host, port);
}
示例#3
0
int 
skynet_socket_listen(struct skynet_context *ctx, const char *host, int port, int backlog) {
	uint32_t source = skynet_context_handle(ctx);
	return socket_server_listen(SOCKET_SERVER, source, host, port, backlog);
}
示例#4
0
/* 异步方式生成一个 UDP 套接字, 如果提供了主机 addr 和端口 port 将把此套接字绑定到此地址上. 如果没有则不绑定,
 * 且其套接字类型为 UDP , 函数可以接收 UDP 和 UDPv6 两种形式的地址, 套接字类型与地址类型一致.
 *
 * 返回: 成功时返回套接字 id, 失败时返回 -1 . */
int 
skynet_socket_udp(struct skynet_context *ctx, const char * addr, int port) {
	uint32_t source = skynet_context_handle(ctx);
	return socket_server_udp(SOCKET_SERVER, source, addr, port);
}
示例#5
0
/* 可对类型为 SOCKET_TYPE_PACCEPT, SOCKET_TYPE_PLISTEN 和 SOCKET_TYPE_CONNECTED 的套接字发起启动命令.
 * 首先将导致前两种套接字开始接收 I/O 事件通知, 其次将导致第三种套接字的所属服务变为服务 ctx . 最终将以异步方式通知
 * 服务成功或失败.
 *
 * 函数无返回值 */
void 
skynet_socket_start(struct skynet_context *ctx, int id) {
	uint32_t source = skynet_context_handle(ctx);
	socket_server_start(SOCKET_SERVER, source, id);
}
示例#6
0
uint32_t
skynet_handle_register(struct skynet_context *ctx) {
	struct handle_storage *s = H;

	// 线程上锁, 保证线程安全
	rwlock_wlock(&s->lock);
	
	for (;;) {	// 注意, 这里是一个无限循环, 必须拿到一个可用的 handle
		int i;

		// 从头开始循环遍历
		for (i=0;i<s->slot_size;i++) {
			uint32_t handle = (i+s->handle_index) & HANDLE_MASK;	// 获得从右到左 3 个字节的数据, 最左的低 4 个字节(高 8 位)用来表示 harbor
			int hash = handle & (s->slot_size-1);					// 获得实际的索引, hash 的值不超出 slot_size 的范围

			// 当有可用的 slot 放入 ctx
			if (s->slot[hash] == NULL) {

				// 记录注册的 ctx
				s->slot[hash] = ctx;

				// handle_index 自增
				s->handle_index = handle + 1;

				// 已经存储了 ctx 了, 可以解锁让其他线程使用了
				rwlock_wunlock(&s->lock);

				// 新的 handle 需要使用高 8 位记录当前 handle 所属的 harbor
				handle |= s->harbor;
				return handle;
			}
		}

		// 当前进程不能超过 HANDLE_MASK 的数量
		assert((s->slot_size*2 - 1) <= HANDLE_MASK);

		// 如果没有可用的空间, 扩展容量
		// 申请新的内存空间, slot_size * 2
		struct skynet_context ** new_slot = skynet_malloc(s->slot_size * 2 * sizeof(struct skynet_context *));

		// 重置内存数据
		memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *));

		// 将原来的内容进行复制
		for (i = 0; i < s->slot_size; i++) {

			// 获得在当前分配的空间中可用的索引, 注意这里是使用  (slot_size * 2 - 1) 在进行为操作.
			int hash = skynet_context_handle(s->slot[i]) & (s->slot_size * 2 - 1);
			assert(new_slot[hash] == NULL);

			// 这里为什么不是直接 new_slot[i] = s->slot[i] 呢, 而要绕个弯拿到 hash, 然后 new_slot[hash] = s->slot[i]
			// 解答, 很有意思的小细节:
			// 首先说 handle_index 从 1 开始计数, 而且都是不断的增加, 返回的时候使用的是 return handle |= s->harbor; 这就决定了返回值不会为 0
			// 在上面的查询 slot, 并且分配 handle 的过程中, 索引是 hash, 返回值是 handle, handle 可以大于 slot_size.
			// 这里获得的 hash 可以是大于 slot_size 的, 那么现在可以举例: hash = 4, i = 0
			// new_slot[4] = s->slot[0], 如果使用 new_slot[i] = s->slot[i] 这种方式, 那么对于结果上来说是没有什么影响的, 但是会出现这样一种情况:
			// 例如: 原来的 slot_size 是 7, 这时 handle_index 16, 全部的 slot 正在被使用. 那么现在需要扩展空间, slot_size 扩展到 16, 那么现在来看看
			// new_slot 的分配情况是如何的:
			// 原来的 slot 是 [0, slot1, slot2, slot3, slot4, slot5, slot6, slot7]
			// 现在的 slot 是 [0, 0, 0, 0, 0, 0, 0, 0, 0, slot1, slot2, slot3, slot4, slot5, slot6, slot7]
			new_slot[hash] = s->slot[i];
		}

		// 释放之前的数据
		skynet_free(s->slot);

		// 记录新的数据
		s->slot = new_slot;
		s->slot_size *= 2;
	}
}